Upgrade ietf-{inet,yang}-types to 2013-07-15
[groupbasedpolicy.git] / neutron-mapper / src / main / java / org / opendaylight / groupbasedpolicy / neutron / mapper / mapping / NeutronRouterAware.java
index 200eae1f435f95cff95cf78ff48348ef25f4474e..a7d14bc1b596596882cfd96e516de716f03a87b3 100644 (file)
@@ -10,56 +10,58 @@ package org.opendaylight.groupbasedpolicy.neutron.mapper.mapping;
 
 import static com.google.common.base.Preconditions.checkNotNull;
 
-import java.util.ArrayList;
 import java.util.List;
 
 import javax.annotation.Nonnull;
-import javax.annotation.Nullable;
 
 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
-import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction;
-import org.opendaylight.controller.md.sal.binding.api.ReadTransaction;
 import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction;
+import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
-import org.opendaylight.groupbasedpolicy.neutron.mapper.infrastructure.Router;
-import org.opendaylight.groupbasedpolicy.neutron.mapper.mapping.rule.NeutronSecurityRuleAware;
+import org.opendaylight.groupbasedpolicy.domain_extension.l2_l3.util.L2L3IidFactory;
+import org.opendaylight.groupbasedpolicy.neutron.gbp.util.NeutronGbpIidFactory;
+import org.opendaylight.groupbasedpolicy.neutron.mapper.EndpointRegistrator;
 import org.opendaylight.groupbasedpolicy.neutron.mapper.util.MappingUtils;
-import org.opendaylight.groupbasedpolicy.neutron.mapper.util.MappingUtils.ForwardingCtx;
-import org.opendaylight.groupbasedpolicy.neutron.mapper.util.NeutronMapperIidFactory;
-import org.opendaylight.groupbasedpolicy.neutron.mapper.util.Utils;
+import org.opendaylight.groupbasedpolicy.neutron.mapper.util.PortUtils;
+import org.opendaylight.groupbasedpolicy.neutron.mapper.util.SubnetUtils;
 import org.opendaylight.groupbasedpolicy.util.DataStoreHelper;
 import org.opendaylight.groupbasedpolicy.util.IidFactory;
-import org.opendaylight.neutron.spi.INeutronPortCRUD;
-import org.opendaylight.neutron.spi.INeutronRouterAware;
-import org.opendaylight.neutron.spi.INeutronSubnetCRUD;
-import org.opendaylight.neutron.spi.NeutronCRUDInterfaces;
-import org.opendaylight.neutron.spi.NeutronPort;
-import org.opendaylight.neutron.spi.NeutronRoute;
-import org.opendaylight.neutron.spi.NeutronRouter;
-import org.opendaylight.neutron.spi.NeutronRouter_Interface;
-import org.opendaylight.neutron.spi.NeutronSubnet;
-import org.opendaylight.neutron.spi.Neutron_IPs;
-import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IpAddress;
-import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IpPrefix;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpPrefix;
+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.groupbasedpolicy.base_endpoint.rev160427.common.endpoint.fields.NetworkContainmentBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.common.endpoint.fields.network.containment.containment.NetworkDomainContainmentBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.register.endpoint.input.AddressEndpointRegBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.ContextId;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.Description;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.L2FloodDomainId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.L2BridgeDomainId;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.L3ContextId;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.Name;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.NetworkDomainId;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.SubnetId;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.TenantId;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.EndpointService;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.UnregisterEndpointInputBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.unregister.endpoint.input.L3;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.unregister.endpoint.input.L3Builder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.neutron.mapper.rev150223.mappings.network.mappings.NetworkMapping;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.endpoints.EndpointL3Key;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.forwarding.l2_l3.rev160427.IpPrefixType;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.forwarding.l2_l3.rev160427.SubnetAugmentForwarding;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.forwarding.l2_l3.rev160427.SubnetAugmentForwardingBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.forwarding.l2_l3.rev160427.has.subnet.Subnet;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.forwarding.l2_l3.rev160427.has.subnet.SubnetBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.forwarding.rev160427.forwarding.forwarding.by.tenant.ForwardingContext;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.forwarding.rev160427.forwarding.forwarding.by.tenant.ForwardingContextBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.forwarding.rev160427.forwarding.forwarding.by.tenant.NetworkDomain;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.forwarding.rev160427.forwarding.forwarding.by.tenant.NetworkDomainBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.forwarding.rev160427.forwarding.forwarding.by.tenant.NetworkDomainKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.neutron.gbp.mapper.rev150513.mappings.neutron.by.gbp.mappings.external.gateways.as.endpoints.ExternalGatewayAsEndpoint;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.neutron.gbp.mapper.rev150513.mappings.neutron.by.gbp.mappings.external.gateways.as.l3.endpoints.ExternalGatewayAsL3Endpoint;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.forwarding.context.L2BridgeDomain;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.forwarding.context.L2BridgeDomainBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.forwarding.context.L3Context;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.forwarding.context.L3ContextBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.forwarding.context.Subnet;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.forwarding.context.SubnetBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.policy.EndpointGroup;
+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.ports.rev150712.port.attributes.FixedIps;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.ports.attributes.ports.Port;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.rev150712.Neutron;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -68,378 +70,278 @@ import com.google.common.base.Optional;
 import com.google.common.base.Strings;
 import com.google.common.collect.ImmutableList;
 
-public class NeutronRouterAware implements INeutronRouterAware {
+public class NeutronRouterAware implements NeutronAware<Router> {
 
     private static final Logger LOG = LoggerFactory.getLogger(NeutronRouterAware.class);
-    private static final String DEFAULT_ROUTE = "0.0.0.0/0";
+    public static final InstanceIdentifier<Router> ROUTER_WILDCARD_IID =
+            InstanceIdentifier.builder(Neutron.class).child(Routers.class).child(Router.class).build();
     private final DataBroker dataProvider;
-    private final  EndpointService epService;
-    private final NeutronSecurityRuleAware secRuleAware;
+    private final EndpointRegistrator epRegistrator;
 
-    public NeutronRouterAware(DataBroker dataProvider, EndpointService epService, NeutronSecurityRuleAware secRuleAware) {
+    public NeutronRouterAware(DataBroker dataProvider, EndpointRegistrator epRegistrator) {
         this.dataProvider = checkNotNull(dataProvider);
-        this.epService = checkNotNull(epService);
-        this.secRuleAware = checkNotNull(secRuleAware);
+        this.epRegistrator = checkNotNull(epRegistrator);
     }
 
     @Override
-    public int canCreateRouter(NeutronRouter router) {
-        LOG.trace("canCreateRouter - {}", router);
-        // nothing to consider
-        return StatusCode.OK;
-    }
-
-    @Override
-    public void neutronRouterCreated(NeutronRouter router) {
-        LOG.trace("neutronRouterCreated - {}", router);
-        // TODO Li msunal external gateway
+    public void onCreated(Router router, Neutron neutron) {
+        LOG.trace("created router - {}", router);
+
+        ContextId routerl3ContextId = new ContextId(router.getUuid().getValue());
+        TenantId tenantId = new TenantId(router.getTenantId().getValue());
+        InstanceIdentifier<ForwardingContext> routerL3CtxIid = L2L3IidFactory.l3ContextIid(tenantId, routerl3ContextId);
+        ForwardingContextBuilder fwdCtxBuilder = new ForwardingContextBuilder();
+        Name routerName = null;
+        if (!Strings.isNullOrEmpty(router.getName())) {
+            try {
+                routerName = new Name(router.getName());
+                fwdCtxBuilder.setName(routerName);
+            } catch (Exception e) {
+                LOG.info("Name '{}' of Neutron Subnet '{}' is ignored.", router.getName(),
+                        router.getUuid().getValue());
+                LOG.debug("Name exception", e);
+            }
+        }
+        ForwardingContext routerl3Context = fwdCtxBuilder.setContextId(routerl3ContextId)
+            .setContextType(MappingUtils.L3_CONTEXT)
+            .build();
+        WriteTransaction wTx = dataProvider.newWriteOnlyTransaction();
+        wTx.put(LogicalDatastoreType.CONFIGURATION, routerL3CtxIid, routerl3Context, true);
+        createTenantL3Context(new L3ContextId(routerl3ContextId), tenantId, routerName, wTx);
+        DataStoreHelper.submitToDs(wTx);
     }
 
-    @Override
-    public int canUpdateRouter(NeutronRouter delta, NeutronRouter original) {
-        LOG.trace("canUpdateRouter - delta: {} original: {}", delta, original);
-        // TODO Li msunal external gateway
-        return StatusCode.OK;
+    @Deprecated
+    private void createTenantL3Context(L3ContextId l3ContextId, TenantId tenantId, Name name, WriteTransaction wTx) {
+        L3ContextBuilder l3ContextBuilder = new L3ContextBuilder();
+        if (name != null) {
+            l3ContextBuilder.setName(name);
+        }
+        L3Context l3Context = l3ContextBuilder.setId(l3ContextId).build();
+        wTx.put(LogicalDatastoreType.CONFIGURATION, IidFactory.l3ContextIid(tenantId, l3ContextId), l3Context, true);
     }
 
     @Override
-    public void neutronRouterUpdated(NeutronRouter router) {
-        LOG.trace("neutronRouterUpdated - {}", router);
-        if (router.getExternalGatewayInfo() == null || router.getExternalGatewayInfo().getExternalFixedIPs() == null) {
-            LOG.trace("neutronRouterUpdated - not an external Gateway");
-            return;
-        }
-
-        NeutronCRUDInterfaces neutronCRUDInterface = new NeutronCRUDInterfaces().fetchINeutronPortCRUD(this);
-        INeutronPortCRUD portInterface = neutronCRUDInterface.getPortInterface();
-        if (portInterface == null) {
-            LOG.warn("Illegal state - No provider for {}", INeutronPortCRUD.class.getName());
-            return;
-        }
+    public void onUpdated(Router oldRouter, Router newRouter, Neutron oldNeutron, Neutron newNeutron) {
+        LOG.trace("updated router - OLD: {}\nNEW: {}", oldRouter, newRouter);
 
         ReadWriteTransaction rwTx = dataProvider.newReadWriteTransaction();
-        TenantId tenantId = new TenantId(Utils.normalizeUuid(router.getTenantID()));
-        L3ContextId l3ContextIdFromRouterId = new L3ContextId(router.getID());
-        InstanceIdentifier<L3Context> l3ContextIidForRouterId = IidFactory.l3ContextIid(tenantId,
-                l3ContextIdFromRouterId);
-        Optional<L3Context> potentialL3ContextForRouter = DataStoreHelper.readFromDs(
-                LogicalDatastoreType.CONFIGURATION, l3ContextIidForRouterId, rwTx);
-        L3Context l3Context = null;
-        if (potentialL3ContextForRouter.isPresent()) {
-            l3Context = potentialL3ContextForRouter.get();
-        } else { // add L3 context if missing
-            l3Context = createL3ContextFromRouter(router);
-            rwTx.put(LogicalDatastoreType.CONFIGURATION, l3ContextIidForRouterId, l3Context);
-        }
-
-        neutronCRUDInterface = neutronCRUDInterface.fetchINeutronSubnetCRUD(this);
-        INeutronSubnetCRUD subnetInterface = neutronCRUDInterface.getSubnetInterface();
-        if (subnetInterface == null) {
-            LOG.warn("Illegal state - No provider for {}", INeutronSubnetCRUD.class.getName());
-            return;
-        }
-        NeutronSubnet defaultSubnet = subnetInterface.getSubnet(router.getExternalGatewayInfo()
-            .getExternalFixedIPs()
-            .get(0)
-            .getSubnetUUID());
-        IpAddress defaultGateway = null;
-        if (defaultSubnet != null) {
-            defaultGateway = Utils.createIpAddress(defaultSubnet.getGatewayIP());
-            //Create L3Endpoint for defaultGateway and write to externalGateways to L3Endpoints in neutron-gbp datastore
-            NetworkDomainId containment = new NetworkDomainId(defaultSubnet.getID());
-            NeutronPortAware.addL3EndpointForExternalGateway(tenantId, l3Context.getId(), defaultGateway, containment ,rwTx);
-        }
-        // Create L3Prefix Endpoints for all routes
-        if (router.getRoutes().isEmpty()) {
-            NeutronRoute defaultRoute = new NeutronRoute();
-            defaultRoute.setDestination(DEFAULT_ROUTE);
-            defaultRoute.setNextHop(Utils.getStringIpAddress(defaultGateway));
-            router.setRoutes(ImmutableList.of(defaultRoute));
-
-        }
-        if (defaultGateway != null) {
-            for (NeutronRoute route : router.getRoutes()) {
-                IpPrefix ipPrefix = Utils.createIpPrefix(route.getDestination());
-                boolean addedL3Prefix = NeutronPortAware.addL3PrefixEndpoint(l3ContextIdFromRouterId, ipPrefix,
-                        defaultGateway, tenantId, epService);
-                if (!addedL3Prefix) {
-                    LOG.warn("Could not add EndpointL3Prefix for Neutron route {} for router {}", route, router.getID());
-                    rwTx.cancel();
-                    return;
-                }
-            }
-        }
-        for (Neutron_IPs externalFixedIp : router.getExternalGatewayInfo().getExternalFixedIPs()) {
-            NeutronPort routerPort = portInterface.getPort(router.getGatewayPortId());
-            IpAddress ipAddress = Utils.createIpAddress(routerPort.getFixedIPs().get(0).getIpAddress());
-            // External subnet associated with gateway port should use the gateway IP not router IP.
-            NeutronSubnet neutronSubnet = subnetInterface.getSubnet(externalFixedIp.getSubnetUUID());
-            ipAddress = Utils.createIpAddress(neutronSubnet.getGatewayIP());
-            SubnetId subnetId = new SubnetId(externalFixedIp.getSubnetUUID());
-            Subnet subnet = resolveSubnetWithVirtualRouterIp(tenantId, subnetId, ipAddress, rwTx);
-            if (subnet == null) {
+        TenantId tenantId = new TenantId(newRouter.getTenantId().getValue());
+        ContextId routerL3CtxId = new ContextId(newRouter.getUuid().getValue());
+
+        if (newRouter.getGatewayPortId() != null && oldRouter.getGatewayPortId() == null) {
+            // external network is attached to router
+            Uuid gatewayPortId = newRouter.getGatewayPortId();
+            Optional<Port> potentialGwPort = PortUtils.findPort(gatewayPortId, newNeutron.getPorts());
+            if (!potentialGwPort.isPresent()) {
+                LOG.warn("Illegal state - router gateway port {} does not exist for router {}.",
+                        gatewayPortId.getValue(), newRouter);
                 rwTx.cancel();
                 return;
             }
-            rwTx.put(LogicalDatastoreType.CONFIGURATION, IidFactory.subnetIid(tenantId, subnet.getId()), subnet);
 
-            if (Strings.isNullOrEmpty(routerPort.getTenantID())) {
-                routerPort.setTenantID(router.getTenantID());
+            Port gwPort = potentialGwPort.get();
+            List<FixedIps> fixedIpsFromGwPort = gwPort.getFixedIps();
+            if (fixedIpsFromGwPort == null || fixedIpsFromGwPort.isEmpty()) {
+                LOG.warn("Illegal state - router gateway port {} does not contain fixed IPs {}",
+                        gatewayPortId.getValue(), gwPort);
+                rwTx.cancel();
+                return;
             }
 
-            boolean isSuccessful = setNewL3ContextToEpsFromSubnet(tenantId, l3Context, subnet, rwTx);
-            if (!isSuccessful) {
+            // router can have only one external network
+            FixedIps ipWithSubnetFromGwPort = fixedIpsFromGwPort.get(0);
+            Optional<org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.subnets.rev150712.subnets.attributes.subnets.Subnet> potentialSubnet = SubnetUtils.findSubnet(ipWithSubnetFromGwPort.getSubnetId(), newNeutron.getSubnets());
+            if (!potentialSubnet.isPresent()) {
+                LOG.warn("Illegal state - Subnet {} does not exist for router {}.",
+                        ipWithSubnetFromGwPort.getSubnetId(), newRouter);
                 rwTx.cancel();
                 return;
             }
+            IpPrefix gatewayIp =  MappingUtils.ipAddressToIpPrefix(potentialSubnet.get().getGatewayIp());
+            boolean registeredExternalGateway = registerExternalGateway(tenantId, gatewayIp,
+                    routerL3CtxId, new NetworkDomainId(ipWithSubnetFromGwPort.getSubnetId().getValue()));
+            if (!registeredExternalGateway) {
+                LOG.warn("Could not add L3Prefix as gateway of default route. Gateway port {}", gwPort);
+                rwTx.cancel();
+                return;
+            }
+            addNeutronExtGwGbpMapping(routerL3CtxId, gatewayIp, rwTx);
+            NetworkDomain subnetDomain = createSubnetWithVirtualRouterIp(gatewayIp, new NetworkDomainId(ipWithSubnetFromGwPort.getSubnetId()
+                .getValue()));
+            rwTx.merge(LogicalDatastoreType.CONFIGURATION, L2L3IidFactory.subnetIid(tenantId, subnetDomain.getNetworkDomainId()),
+                    subnetDomain);
+            ContextId l2BdId = new ContextId(potentialSubnet.get().getNetworkId().getValue());
+            Optional<ForwardingContext> optBd = DataStoreHelper.readFromDs(LogicalDatastoreType.CONFIGURATION,
+                    L2L3IidFactory.l2BridgeDomainIid(tenantId, l2BdId), rwTx);
+            if (!optBd.isPresent()) {
+                LOG.warn(
+                        "Could not read L2-Bridge-Domain {}. Modification of its parent to L3-Context of router {} aborted.",
+                        l2BdId, newRouter.getUuid());
+                rwTx.cancel();
+                return;
+            }
+            ForwardingContext l2BdWithGw = new ForwardingContextBuilder(optBd.get())
+            .setParent(MappingUtils.createParent(routerL3CtxId, MappingUtils.L3_CONTEXT))
+            .build();
+            rwTx.put(LogicalDatastoreType.CONFIGURATION, L2L3IidFactory.l2BridgeDomainIid(tenantId, l2BdId),
+                    l2BdWithGw);
         }
-
+        updateTenantForwarding(newNeutron, oldRouter, newRouter, new L3ContextId(routerL3CtxId), tenantId, rwTx);
         DataStoreHelper.submitToDs(rwTx);
     }
 
-    @Override
-    public int canDeleteRouter(NeutronRouter router) {
-        LOG.trace("canDeleteRouter - {}", router);
-        // nothing to consider
-        return StatusCode.OK;
+    private boolean registerExternalGateway(TenantId tenantId, IpPrefix ipPrefix, ContextId routerl3ContextId,
+            NetworkDomainId networkDomainId) {
+        AddressEndpointRegBuilder addrEpBuilder = new AddressEndpointRegBuilder();
+        addrEpBuilder.setAddressType(IpPrefixType.class);
+        addrEpBuilder.setAddress(MappingUtils.ipPrefixToStringIpAddress(ipPrefix));
+        addrEpBuilder.setContextId(routerl3ContextId);
+        addrEpBuilder.setContextType(MappingUtils.L3_CONTEXT);
+        addrEpBuilder.setTenant(tenantId);
+        addrEpBuilder.setNetworkContainment(new NetworkContainmentBuilder().setContainment(
+                new NetworkDomainContainmentBuilder().setNetworkDomainId(networkDomainId).build()).build());
+        addrEpBuilder.setEndpointGroup(ImmutableList.of(MappingUtils.EPG_EXTERNAL_ID));
+        addrEpBuilder.setTimestamp(System.currentTimeMillis());
+        return epRegistrator.registerEndpoint(addrEpBuilder.build());
     }
 
-    @Override
-    public void neutronRouterDeleted(NeutronRouter router) {
-        LOG.trace("neutronRouterDeleted - {}", router);
-        ReadWriteTransaction rwTx = dataProvider.newReadWriteTransaction();
-        TenantId tenantId = new TenantId(Utils.normalizeUuid(router.getTenantID()));
-        Optional<EndpointGroup> potentialEpg = DataStoreHelper.removeIfExists(LogicalDatastoreType.CONFIGURATION,
-                IidFactory.endpointGroupIid(tenantId, Router.EPG_ID), rwTx);
-        if (!potentialEpg.isPresent()) {
-            LOG.warn("Illegal state - Endpoint group {} does not exist.", Router.EPG_ID.getValue());
-            rwTx.cancel();
-            return;
-        }
-        DataStoreHelper.submitToDs(rwTx);
+    private NetworkDomain createSubnetWithVirtualRouterIp(IpPrefix gatewayIp, NetworkDomainId subnetId) {
+        Subnet subnet = new SubnetBuilder().setVirtualRouterIp(MappingUtils.ipPrefixToIpAddress(gatewayIp.getValue())).build();
+        return new NetworkDomainBuilder().setKey(new NetworkDomainKey(subnetId, MappingUtils.SUBNET))
+            .addAugmentation(SubnetAugmentForwarding.class,
+                    new SubnetAugmentForwardingBuilder().setSubnet(subnet).build())
+            .build();
     }
 
-    @Override
-    public int canAttachInterface(NeutronRouter router, NeutronRouter_Interface routerInterface) {
-        LOG.trace("canAttachInterface - router: {} interface: {}", router, routerInterface);
-        try (ReadOnlyTransaction rTx = dataProvider.newReadOnlyTransaction()) {
-            L3ContextId l3ContextIdFromRouterId = new L3ContextId(router.getID());
-            TenantId tenantId = new TenantId(Utils.normalizeUuid(router.getTenantID()));
-            SubnetId subnetId = new SubnetId(routerInterface.getSubnetUUID());
-            Optional<Subnet> potentialSubnet = DataStoreHelper.readFromDs(LogicalDatastoreType.CONFIGURATION,
-                    IidFactory.subnetIid(tenantId, subnetId), rTx);
-            if (!potentialSubnet.isPresent()) {
-                LOG.warn("Illegal state - subnet {} does not exist.", subnetId.getValue());
-                return StatusCode.NOT_FOUND;
-            }
-            Subnet subnet = potentialSubnet.get();
-            L2FloodDomainId l2FdId = new L2FloodDomainId(subnet.getParent().getValue());
-            ForwardingCtx fwCtx = MappingUtils.createForwardingContext(tenantId, l2FdId, rTx);
-            if (fwCtx.getL3Context() != null && fwCtx.getL3Context().getId().equals(l3ContextIdFromRouterId)) {
-                // TODO Be msunal
-                LOG.warn("Illegal state - Neutron mapper does not support multiple router interfaces in the same subnet yet.");
-                return StatusCode.FORBIDDEN;
-            }
-            return StatusCode.OK;
-        }
+    @Deprecated
+    private void updateTenantForwarding(Neutron newNeutron, Router oldRouter, Router newRouter, L3ContextId l3ContextId, TenantId tenantId, ReadWriteTransaction rwTx) {
+        InstanceIdentifier<L3Context> l3ContextIid =
+                IidFactory.l3ContextIid(tenantId, l3ContextId);
+         Optional<L3Context> optL3Context = DataStoreHelper.readFromDs(LogicalDatastoreType.CONFIGURATION, l3ContextIid, rwTx);
+         L3Context l3Context = null;
+         if (optL3Context.isPresent()) {
+             l3Context = optL3Context.get();
+         } else { // add L3 context if missing
+             l3Context = createL3CtxFromRouter(newRouter);
+             rwTx.put(LogicalDatastoreType.CONFIGURATION, l3ContextIid, l3Context, true);
+         }
+
+         if (newRouter.getGatewayPortId() != null && oldRouter.getGatewayPortId() == null) {
+             // external network is attached to router
+             Uuid gatewayPortId = newRouter.getGatewayPortId();
+             Optional<Port> potentialGwPort = PortUtils.findPort(gatewayPortId, newNeutron.getPorts());
+             if (!potentialGwPort.isPresent()) {
+                 LOG.warn("Illegal state - router gateway port {} does not exist for router {}.",
+                         gatewayPortId.getValue(), newRouter);
+                 rwTx.cancel();
+                 return;
+             }
+
+             Port gwPort = potentialGwPort.get();
+             List<FixedIps> fixedIpsFromGwPort = gwPort.getFixedIps();
+             if (fixedIpsFromGwPort == null || fixedIpsFromGwPort.isEmpty()) {
+                 LOG.warn("Illegal state - router gateway port {} does not contain fixed IPs {}",
+                         gatewayPortId.getValue(), gwPort);
+                 rwTx.cancel();
+                 return;
+             }
+
+             // router can have only one external network
+             FixedIps ipWithSubnetFromGwPort = fixedIpsFromGwPort.get(0);
+             Optional<org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.subnets.rev150712.subnets.attributes.subnets.Subnet> potentialSubnet = SubnetUtils.findSubnet(ipWithSubnetFromGwPort.getSubnetId(), newNeutron.getSubnets());
+             if (!potentialSubnet.isPresent()) {
+                 LOG.warn("Illegal state - Subnet {} does not exist for router {}.",
+                         ipWithSubnetFromGwPort.getSubnetId(), newRouter);
+                 rwTx.cancel();
+                 return;
+             }
+             IpAddress gatewayIp =  potentialSubnet.get().getGatewayIp();
+             NetworkDomainId networkContainment = new NetworkDomainId(ipWithSubnetFromGwPort.getSubnetId().getValue());
+             boolean registeredExternalGateway = epRegistrator.registerL3EpAsExternalGateway(tenantId, gatewayIp,
+                     l3ContextId, networkContainment);
+             if (!registeredExternalGateway) {
+                 LOG.warn("Could not add L3Prefix as gateway of default route. Gateway port {}", gwPort);
+                 rwTx.cancel();
+                 return;
+             }
+             EndpointL3Key epL3Key = new EndpointL3Key(gatewayIp, l3ContextId);
+             addNeutronExtGwMapping(epL3Key, rwTx);
+
+             boolean registeredDefaultRoute = epRegistrator.registerExternalL3PrefixEndpoint(MappingUtils.DEFAULT_ROUTE,
+                     l3ContextId, gatewayIp, tenantId);
+             if (!registeredDefaultRoute) {
+                 LOG.warn("Could not add EndpointL3Prefix as default route. Gateway port {}", gwPort);
+                 rwTx.cancel();
+                 return;
+             }
+             org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.forwarding.context.Subnet subnetWithGw =
+                     new org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.forwarding.context.SubnetBuilder().setId(new SubnetId(ipWithSubnetFromGwPort.getSubnetId().getValue()))
+                         .setVirtualRouterIp(gatewayIp)
+                 .build();
+             rwTx.merge(LogicalDatastoreType.CONFIGURATION, IidFactory.subnetIid(tenantId, subnetWithGw.getId()),
+                     subnetWithGw);
+             L2BridgeDomainId l2BdId = new L2BridgeDomainId(potentialSubnet.get().getNetworkId().getValue());
+             Optional<L2BridgeDomain> optBd = DataStoreHelper.readFromDs(LogicalDatastoreType.CONFIGURATION,
+                     IidFactory.l2BridgeDomainIid(tenantId, l2BdId), rwTx);
+             if (!optBd.isPresent()) {
+                 LOG.warn(
+                         "Could not read L2-Bridge-Domain {}. Modification of its parent to L3-Context of router {} aborted.",
+                         l2BdId, newRouter.getUuid());
+                 rwTx.cancel();
+                 return;
+             }
+             L2BridgeDomain l2BdWithGw = new L2BridgeDomainBuilder(optBd.get())
+                 .setParent(new L3ContextId(l3ContextId.getValue()))
+                 .build();
+             rwTx.put(LogicalDatastoreType.CONFIGURATION, IidFactory.l2BridgeDomainIid(tenantId, l2BdId),
+                     l2BdWithGw);
+         } 
     }
 
-    @Override
-    public void neutronRouterInterfaceAttached(NeutronRouter router, NeutronRouter_Interface routerInterface) {
-        LOG.trace("neutronRouterInterfaceAttached - router: {} interface: {}", router, routerInterface);
-        NeutronCRUDInterfaces neutronCRUDInterface = new NeutronCRUDInterfaces().fetchINeutronPortCRUD(this);
-        INeutronPortCRUD portInterface = neutronCRUDInterface.getPortInterface();
-        if (portInterface == null) {
-            LOG.warn("Illegal state - No provider for {}", INeutronPortCRUD.class.getName());
-            return;
-        }
-
-        ReadWriteTransaction rwTx = dataProvider.newReadWriteTransaction();
-        TenantId tenantId = new TenantId(Utils.normalizeUuid(router.getTenantID()));
-        L3ContextId l3ContextIdFromRouterId = new L3ContextId(router.getID());
-        InstanceIdentifier<L3Context> l3ContextIidForRouterId = IidFactory.l3ContextIid(tenantId,
-                l3ContextIdFromRouterId);
-        Optional<L3Context> potentialL3ContextForRouter = DataStoreHelper.readFromDs(
-                LogicalDatastoreType.CONFIGURATION, l3ContextIidForRouterId, rwTx);
-        L3Context l3Context = null;
-        if (potentialL3ContextForRouter.isPresent()) {
-            l3Context = potentialL3ContextForRouter.get();
-        } else { // add L3 context if missing
-            l3Context = createL3ContextFromRouter(router);
-            rwTx.put(LogicalDatastoreType.CONFIGURATION, l3ContextIidForRouterId, l3Context);
-        }
-
-        // Based on Neutron Northbound - Port representing router interface
-        // contains exactly on fixed IP
-        NeutronPort routerPort = portInterface.getPort(routerInterface.getPortUUID());
-        SubnetId subnetId = new SubnetId(routerInterface.getSubnetUUID());
-        IpAddress ipAddress = Utils.createIpAddress(routerPort.getFixedIPs().get(0).getIpAddress());
-        Subnet subnet = resolveSubnetWithVirtualRouterIp(tenantId, subnetId, ipAddress, rwTx);
-        if (subnet == null) {
-            rwTx.cancel();
-            return;
-        }
-        rwTx.put(LogicalDatastoreType.CONFIGURATION, IidFactory.subnetIid(tenantId, subnet.getId()), subnet);
-
-        boolean isSuccessful = setNewL3ContextToEpsFromSubnet(tenantId, l3Context, subnet, rwTx);
-        if (!isSuccessful) {
-            rwTx.cancel();
-            return;
+    private static @Nonnull ForwardingContext createL3ContextFromRouter(
+            Router router) {
+        Name l3ContextName = null;
+        if (!Strings.isNullOrEmpty(router.getName())) {
+            l3ContextName = new Name(router.getName());
         }
-
-        DataStoreHelper.submitToDs(rwTx);
+        return new ForwardingContextBuilder().setContextId(new ContextId(router.getUuid().getValue()))
+            .setContextType(MappingUtils.L3_CONTEXT)
+            .setName(new Name(l3ContextName.getValue()))
+            .build();
     }
 
-    private static @Nonnull L3Context createL3ContextFromRouter(NeutronRouter router) {
+    @Deprecated
+    private static @Nonnull L3Context createL3CtxFromRouter(Router router) {
         Name l3ContextName = null;
         if (!Strings.isNullOrEmpty(router.getName())) {
             l3ContextName = new Name(router.getName());
         }
-        return new L3ContextBuilder().setId(new L3ContextId(router.getID()))
+        return new L3ContextBuilder().setId(new L3ContextId(router.getUuid().getValue()))
             .setName(l3ContextName)
-            .setDescription(new Description(MappingUtils.NEUTRON_ROUTER + router.getID()))
+            .setDescription(new Description(MappingUtils.NEUTRON_ROUTER + router.getUuid().getValue()))
             .build();
     }
 
-    private @Nullable Subnet resolveSubnetWithVirtualRouterIp(TenantId tenantId, SubnetId subnetId,
-            IpAddress ipAddress, ReadTransaction rTx) {
-        Optional<Subnet> potentialSubnet = DataStoreHelper.readFromDs(LogicalDatastoreType.CONFIGURATION,
-                IidFactory.subnetIid(tenantId, subnetId), rTx);
-        if (!potentialSubnet.isPresent()) {
-            LOG.warn("Illegal state - subnet {} does not exist.", subnetId.getValue());
-            return null;
-        }
-
-        // TODO: Li alagalah: Add gateways and prefixes instead of
-        // VirtualRouterID
-        return new SubnetBuilder(potentialSubnet.get()).setVirtualRouterIp(ipAddress).build();
+    private static void addNeutronExtGwGbpMapping(ContextId contextId, IpPrefix ipPrefix, ReadWriteTransaction rwTx) {
+        ExternalGatewayAsEndpoint externalGatewayL3Endpoint = MappingFactory.createEaxternalGatewayAsEndpoint(
+                contextId, ipPrefix);
+        rwTx.put(LogicalDatastoreType.OPERATIONAL,
+                NeutronGbpIidFactory.externalGatewayAsEndpoint(contextId, ipPrefix, MappingUtils.L3_CONTEXT), externalGatewayL3Endpoint, true);
     }
 
-    /**
-     * @return {@code false} if illegal state occurred; {@code true} otherwise
-     */
-    public boolean setNewL3ContextToEpsFromSubnet(TenantId tenantId, L3Context l3Context, Subnet subnet,
-            ReadWriteTransaction rwTx) {
-        if (subnet.getParent() == null) {
-            LOG.warn("Illegal state - subnet {} does not have a parent.", subnet.getId().getValue());
-            return false;
-        }
-
-        L2FloodDomainId l2FdId = new L2FloodDomainId(subnet.getParent().getValue());
-        ForwardingCtx fwCtx = MappingUtils.createForwardingContext(tenantId, l2FdId, rwTx);
-        if (fwCtx.getL2BridgeDomain() == null) {
-            LOG.warn("Illegal state - l2-flood-domain {} does not have a parent.", l2FdId.getValue());
-            return false;
-        }
-
-        L2BridgeDomain l2BridgeDomain = new L2BridgeDomainBuilder(fwCtx.getL2BridgeDomain()).setParent(
-                l3Context.getId()).build();
-        rwTx.put(LogicalDatastoreType.CONFIGURATION, IidFactory.l2BridgeDomainIid(tenantId, l2BridgeDomain.getId()),
-                l2BridgeDomain);
-
-        NeutronCRUDInterfaces neutronCRUDInterface = new NeutronCRUDInterfaces().fetchINeutronSubnetCRUD(this);
-        INeutronSubnetCRUD subnetInterface = neutronCRUDInterface.getSubnetInterface();
-        if (subnetInterface == null) {
-            LOG.warn("Illegal state - No provider for {}", INeutronSubnetCRUD.class.getName());
-            return false;
-        }
-
-        List<L3> l3Eps = new ArrayList<>();
-        L3ContextId oldL3ContextId = fwCtx.getL3Context().getId();
-        NeutronSubnet neutronSubnet = subnetInterface.getSubnet(subnet.getId().getValue());
-        List<NeutronPort> portsInNeutronSubnet = neutronSubnet.getPortsInSubnet();
-        for (NeutronPort port : portsInNeutronSubnet) {
-            boolean isPortAdded = NeutronPortAware.addNeutronPort(port, rwTx, epService);
-            if (!isPortAdded) {
-                return false;
-            }
-            // TODO Li msunal this has to be rewrite when OFOverlay renderer
-            // will support l3-endpoints.
-            Neutron_IPs firstIp = MappingUtils.getFirstIp(port.getFixedIPs());
-            if (firstIp != null) {
-                l3Eps.add(new L3Builder().setL3Context(oldL3ContextId)
-                    .setIpAddress(Utils.createIpAddress(firstIp.getIpAddress()))
-                    .build());
-            }
-        }
-        if (neutronSubnet.getGatewayIP() != null) {
-            l3Eps.add(new L3Builder().setL3Context(oldL3ContextId)
-                    .setIpAddress(Utils.createIpAddress(neutronSubnet.getGatewayIP()))
-                    .build());
-        }
-
-        if (!l3Eps.isEmpty()) {
-            epService.unregisterEndpoint(new UnregisterEndpointInputBuilder().setL3(l3Eps).build());
-        }
-        return true;
-    }
-
-    @Override
-    public int canDetachInterface(NeutronRouter router, NeutronRouter_Interface routerInterface) {
-        LOG.trace("canDetachInterface - router: {} interface: {}", router, routerInterface);
-        // nothing to consider
-        return StatusCode.OK;
+    @Deprecated
+    private static void addNeutronExtGwMapping(EndpointL3Key epL3Key, ReadWriteTransaction rwTx) {
+        ExternalGatewayAsL3Endpoint externalGatewayL3Endpoint =
+                MappingFactory.createExternalGatewayByL3Endpoint(epL3Key);
+        rwTx.put(LogicalDatastoreType.OPERATIONAL,
+                NeutronGbpIidFactory.externalGatewayAsL3Endpoint(epL3Key.getL3Context(), epL3Key.getIpAddress()),
+                externalGatewayL3Endpoint, true);
     }
 
     @Override
-    public void neutronRouterInterfaceDetached(NeutronRouter router, NeutronRouter_Interface routerInterface) {
-        LOG.trace("neutronRouterInterfaceDetached - router: {} interface: {}", router, routerInterface);
-        NeutronCRUDInterfaces neutronCRUDInterface = new NeutronCRUDInterfaces().fetchINeutronSubnetCRUD(this);
-        INeutronSubnetCRUD subnetInterface = neutronCRUDInterface.getSubnetInterface();
-        if (subnetInterface == null) {
-            LOG.warn("Illegal state - No provider for {}", INeutronSubnetCRUD.class.getName());
-            return;
-        }
-
-        ReadWriteTransaction rwTx = dataProvider.newReadWriteTransaction();
-        TenantId tenantId = new TenantId(Utils.normalizeUuid(router.getTenantID()));
-        L3ContextId l3ContextId = new L3ContextId(router.getID());
-        SubnetId subnetId = new SubnetId(routerInterface.getSubnetUUID());
-        InstanceIdentifier<L3Context> l3ContextIid = IidFactory.l3ContextIid(tenantId, l3ContextId);
-        DataStoreHelper.removeIfExists(LogicalDatastoreType.CONFIGURATION,
-                IidFactory.l3ContextIid(tenantId, l3ContextId), rwTx);
-
-        Optional<Subnet> potentialSubnet = DataStoreHelper.readFromDs(LogicalDatastoreType.CONFIGURATION,
-                IidFactory.subnetIid(tenantId, subnetId), rwTx);
-        if (!potentialSubnet.isPresent()) {
-            LOG.warn("Illegal state - subnet {} does not exist.", subnetId.getValue());
-            rwTx.cancel();
-            return;
-        }
-
-        Subnet subnet = new SubnetBuilder(potentialSubnet.get()).setVirtualRouterIp(null).build();
-        rwTx.put(LogicalDatastoreType.CONFIGURATION, IidFactory.subnetIid(tenantId, subnetId), subnet);
-
-        L2FloodDomainId l2FdId = new L2FloodDomainId(subnet.getParent().getValue());
-        ForwardingCtx fwCtx = MappingUtils.createForwardingContext(tenantId, l2FdId, rwTx);
-        if (fwCtx.getL2BridgeDomain() == null) {
-            LOG.warn("Illegal state - l2-flood-domain {} does not have a parent.", l2FdId.getValue());
-            rwTx.cancel();
-            return;
-        }
-
-        Optional<NetworkMapping> potentialNetworkMapping = DataStoreHelper.readFromDs(LogicalDatastoreType.OPERATIONAL,
-                NeutronMapperIidFactory.networkMappingIid(l2FdId), rwTx);
-        if (!potentialNetworkMapping.isPresent()) {
-            LOG.warn("Illegal state - network-mapping {} does not exist.", l2FdId.getValue());
-            rwTx.cancel();
-            return;
-        }
-
-        L2BridgeDomain l2BridgeDomain = new L2BridgeDomainBuilder(fwCtx.getL2BridgeDomain()).setParent(
-                potentialNetworkMapping.get().getL3ContextId()).build();
-        rwTx.put(LogicalDatastoreType.CONFIGURATION, IidFactory.l2BridgeDomainIid(tenantId, l2BridgeDomain.getId()),
-                l2BridgeDomain);
-
-        NeutronSubnet neutronSubnet = subnetInterface.getSubnet(subnetId.getValue());
-        List<NeutronPort> portsInNeutronSubnet = neutronSubnet.getPortsInSubnet();
-        for (NeutronPort port : portsInNeutronSubnet) {
-            boolean isPortAdded = NeutronPortAware.addNeutronPort(port, rwTx, epService);
-            if (!isPortAdded) {
-                rwTx.cancel();
-                return;
-            }
-        }
+    public void onDeleted(Router router, Neutron oldNeutron, Neutron newNeutron) {
+        LOG.trace("deleted router - {}", router);
     }
 
 }