Neutron port removal fixed
[groupbasedpolicy.git] / neutron-mapper / src / main / java / org / opendaylight / groupbasedpolicy / neutron / mapper / mapping / NeutronPortAware.java
index 86fc91c845d4f7bf5336db2cada62b652240feec..07a0129a81c9dcd1d3042f2fa58794e87cd08972 100644 (file)
@@ -10,696 +10,698 @@ package org.opendaylight.groupbasedpolicy.neutron.mapper.mapping;
 import static com.google.common.base.Preconditions.checkNotNull;
 
 import java.util.ArrayList;
-import java.util.Collection;
-import java.util.HashMap;
-import java.util.HashSet;
 import java.util.List;
-import java.util.Map;
 import java.util.Set;
-import java.util.concurrent.ExecutionException;
 
+import javax.annotation.Nullable;
+
+import com.sun.jndi.cosnaming.IiopUrl;
 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.ReadWriteTransaction;
+import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+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.infrastructure.NetworkClient;
 import org.opendaylight.groupbasedpolicy.neutron.mapper.infrastructure.NetworkService;
-import org.opendaylight.groupbasedpolicy.neutron.mapper.infrastructure.Router;
-import org.opendaylight.groupbasedpolicy.neutron.mapper.mapping.group.NeutronSecurityGroupAware;
-import org.opendaylight.groupbasedpolicy.neutron.mapper.mapping.rule.NeutronSecurityRuleAware;
 import org.opendaylight.groupbasedpolicy.neutron.mapper.util.MappingUtils;
-import org.opendaylight.groupbasedpolicy.neutron.mapper.util.MappingUtils.ForwardingCtx;
-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.INeutronPortAware;
-import org.opendaylight.neutron.spi.NeutronPort;
-import org.opendaylight.neutron.spi.NeutronSecurityGroup;
-import org.opendaylight.neutron.spi.NeutronSecurityRule;
-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.yang.types.rev100924.MacAddress;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.MacAddress;
+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.RegisterEndpointInput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.RegisterEndpointInputBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.UnregisterEndpointInput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.UnregisterEndpointInputBuilder;
+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.endpoints.address.endpoints.AddressEndpointKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.has.child.endpoints.ChildEndpoint;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.has.child.endpoints.ChildEndpointBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.parent.child.endpoints.parent.endpoint.choice.ParentEndpointCaseBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.parent.child.endpoints.parent.endpoint.choice.parent.endpoint._case.ParentEndpoint;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.parent.child.endpoints.parent.endpoint.choice.parent.endpoint._case.ParentEndpointBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.register.endpoint.input.AddressEndpointReg;
+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.base_endpoint.rev160427.unregister.endpoint.input.AddressEndpointUnreg;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.unregister.endpoint.input.AddressEndpointUnregBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.ContextId;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.EndpointGroupId;
-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.common.rev140421.UniqueId;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.EndpointService;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.RegisterEndpointInput;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.RegisterEndpointInputBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.RegisterL3PrefixEndpointInput;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.RegisterL3PrefixEndpointInputBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.UnregisterEndpointInput;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.UnregisterEndpointInputBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.endpoint.fields.L3Address;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.endpoint.fields.L3AddressBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.endpoint.l3.prefix.fields.EndpointL3Gateways;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.endpoint.l3.prefix.fields.EndpointL3GatewaysBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.endpoints.Endpoint;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.endpoints.EndpointKey;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.endpoints.EndpointL3;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.endpoints.EndpointL3Builder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.endpoints.EndpointL3Key;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.endpoints.EndpointL3PrefixKey;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.unregister.endpoint.input.L2;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.unregister.endpoint.input.L2Builder;
 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.gbp.mapper.rev150513.mappings.gbp.by.neutron.mappings.endpoints.by.floating.ip.ports.EndpointByFloatingIpPort;
+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.L3Context;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.forwarding.l2_l3.rev160427.MacAddressType;
+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.neutron.gbp.mapper.rev150513.mappings.gbp.by.neutron.mappings.base.endpoints.by.ports.BaseEndpointByPort;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.neutron.gbp.mapper.rev150513.mappings.gbp.by.neutron.mappings.endpoints.by.ports.EndpointByPort;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.neutron.gbp.mapper.rev150513.mappings.gbp.by.neutron.mappings.endpoints.by.router._interface.ports.EndpointByRouterInterfacePort;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.neutron.gbp.mapper.rev150513.mappings.gbp.by.neutron.mappings.endpoints.by.router.gateway.ports.EndpointByRouterGatewayPort;
-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.neutron.gbp.mapper.rev150513.mappings.neutron.by.gbp.mappings.floating.ip.ports.by.endpoints.FloatingIpPortByEndpoint;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.neutron.gbp.mapper.rev150513.mappings.neutron.by.gbp.mappings.ports.by.base.endpoints.PortByBaseEndpoint;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.neutron.gbp.mapper.rev150513.mappings.neutron.by.gbp.mappings.ports.by.base.endpoints.PortByBaseEndpointKey;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.neutron.gbp.mapper.rev150513.mappings.neutron.by.gbp.mappings.ports.by.endpoints.PortByEndpoint;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.neutron.gbp.mapper.rev150513.mappings.neutron.by.gbp.mappings.router._interface.ports.by.endpoints.RouterInterfacePortByEndpoint;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.neutron.gbp.mapper.rev150513.mappings.neutron.by.gbp.mappings.router.gateway.ports.by.endpoints.RouterGatewayPortByEndpoint;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.ofoverlay.rev140528.EndpointLocation.LocationType;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.ofoverlay.rev140528.OfOverlayContextInput;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.ofoverlay.rev140528.OfOverlayContextInputBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.EndpointGroup;
+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.neutron.binding.rev150712.PortBindingExtension;
+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;
+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.yang.gen.v1.urn.opendaylight.neutron.subnets.rev150712.subnets.attributes.subnets.Subnet;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
-import org.opendaylight.yangtools.yang.common.RpcResult;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import com.google.common.base.Function;
 import com.google.common.base.Optional;
-import com.google.common.base.Strings;
-import com.google.common.collect.Collections2;
 import com.google.common.collect.ImmutableList;
 
-public class NeutronPortAware implements INeutronPortAware {
+public class NeutronPortAware implements NeutronAware<Port> {
 
-    public static final Logger LOG = LoggerFactory.getLogger(NeutronPortAware.class);
-    private static final String DEVICE_OWNER_DHCP = "network:dhcp";
-    private static final String DEVICE_OWNER_ROUTER_IFACE = "network:router_interface";
-    private static final String DEVICE_OWNER_ROUTER_GATEWAY = "network:router_gateway";
-    private static final String DEVICE_OWNER_FLOATING_IP = "network:floatingip";
+    private static final Logger LOG = LoggerFactory.getLogger(NeutronPortAware.class);
+    public static final InstanceIdentifier<Port> PORT_WILDCARD_IID =
+            InstanceIdentifier.builder(Neutron.class).child(Ports.class).child(Port.class).build();
     private final DataBroker dataProvider;
-    private final EndpointService epService;
-    private final NeutronSecurityRuleAware secRuleAware;
-    private final NeutronSecurityGroupAware secGrpAware;
-    private final static Map<String, UniqueId> floatingIpPortByDeviceId = new HashMap<>();
-    private final Set<TenantId> tenantsWithNetworkSeviceEntities = new HashSet<>();
+    private final EndpointRegistrator epRegistrator;
 
-    public NeutronPortAware(DataBroker dataProvider, EndpointService epService, NeutronSecurityRuleAware secRuleAware, NeutronSecurityGroupAware secGrpAware) {
+    public NeutronPortAware(DataBroker dataProvider, EndpointRegistrator epRegistrator) {
         this.dataProvider = checkNotNull(dataProvider);
-        this.epService = checkNotNull(epService);
-        this.secRuleAware = checkNotNull(secRuleAware);
-        this.secGrpAware = secGrpAware;
+        this.epRegistrator = checkNotNull(epRegistrator);
     }
 
-    /**
-     * @see org.opendaylight.neutron.spi.INeutronPortAware#canCreatePort(org.opendaylight.neutron.spi.NeutronPort)
-     */
-    @Override
-    public int canCreatePort(NeutronPort port) {
-        LOG.trace("canCreatePort - {}", port);
-        // TODO Li msunal this has to be rewrite when OFOverlay renderer will support l3-endpoints.
-        List<Neutron_IPs> fixedIPs = port.getFixedIPs();
-        if (fixedIPs != null && fixedIPs.size() > 1) {
-            LOG.warn("Neutron mapper does not support multiple IPs on the same port.");
-            return StatusCode.BAD_REQUEST;
-        }
-        return StatusCode.OK;
+    @Override public void onCreated(Port createdItem, Neutron neutron) {
+        onCreated(createdItem, neutron, true);
     }
 
-    /**
-     * @see org.opendaylight.neutron.spi.INeutronPortAware#neutronPortCreated(org.opendaylight.neutron.spi.NeutronPort)
-     */
-    @Override
-    public void neutronPortCreated(NeutronPort port) {
-        LOG.trace("neutronPortCreated - {}", port);
-        if (isRouterInterfacePort(port)) {
-            LOG.trace("Port is router interface - {} does nothing. {} handles router iface.",
-                    NeutronPortAware.class.getSimpleName(), NeutronRouterAware.class.getSimpleName());
-            return;
-        }
-        if (isRouterGatewayPort(port)) {
-            LOG.trace("Port is router gateway - {} does nothing. {} handles router iface.",
-                    NeutronPortAware.class.getSimpleName(), NeutronRouterAware.class.getSimpleName());
-            return;
-        }
-        if (isFloatingIpPort(port)) {
-            LOG.trace("Port is floating ip - {} device id - {}", port.getID(), port.getDeviceID());
-            floatingIpPortByDeviceId.put(port.getDeviceID(), new UniqueId(port.getID()));
-            return;
-        }
-        ReadWriteTransaction rwTx = dataProvider.newReadWriteTransaction();
-        TenantId tenantId = new TenantId(Utils.normalizeUuid(port.getTenantID()));
-        if (isDhcpPort(port)) {
-            LOG.trace("Port is DHCP port. - {}", port.getID());
-            Neutron_IPs firstIp = MappingUtils.getFirstIp(port.getFixedIPs());
-            if (firstIp == null) {
-                LOG.warn("Illegal state - DHCP port does not have an IP address.");
-                rwTx.cancel();
+    public void onCreated(Port port, Neutron neutron, boolean addBaseEpMapping) {
+        LOG.trace("created port - {}", port);
+        if (PortUtils.isRouterInterfacePort(port)) {
+            LOG.trace("Port is router interface port: {}", port.getUuid().getValue());
+            // router interface port can have only one IP
+            Optional<FixedIps> potentialPortIpWithSubnet = PortUtils.resolveFirstFixedIps(port);
+            if (!potentialPortIpWithSubnet.isPresent()) {
+                LOG.warn("Illegal state - router interface port does not contain fixed IPs {}",
+                        port);
                 return;
             }
-            if (!tenantsWithNetworkSeviceEntities.contains(tenantId)) {
-                tenantsWithNetworkSeviceEntities.add(tenantId);
-                NetworkService.writeNetworkServiceEntitiesToTenant(tenantId, rwTx);
-                NetworkService.writeDhcpClauseWithConsProvEic(tenantId, null, rwTx);
-                NetworkService.writeDnsClauseWithConsProvEic(tenantId, null, rwTx);
-                NetworkClient.writeNetworkClientEntitiesToTenant(tenantId, rwTx);
-                NetworkClient.writeConsumerNamedSelector(tenantId, NetworkService.DHCP_CONTRACT_CONSUMER_SELECTOR, rwTx);
-                NetworkClient.writeConsumerNamedSelector(tenantId, NetworkService.DNS_CONTRACT_CONSUMER_SELECTOR, rwTx);
-            }
-        } else {
-            // this is here b/c stable/kilo sends sec-groups only with port
-            List<NeutronSecurityGroup> secGroups = port.getSecurityGroups();
-            if (secGroups != null) {
-                for (NeutronSecurityGroup secGroup : secGroups) {
-                    EndpointGroupId epgId = new EndpointGroupId(secGroup.getSecurityGroupUUID());
-                    Optional<EndpointGroup> potentialEpg = DataStoreHelper.readFromDs(LogicalDatastoreType.CONFIGURATION,
-                            IidFactory.endpointGroupIid(tenantId, epgId), rwTx);
-                    if (!potentialEpg.isPresent()) {
-                        boolean isSecGroupCreated = secGrpAware.addNeutronSecurityGroup(secGroup, rwTx);
-                        if (!isSecGroupCreated) {
-                            rwTx.cancel();
-                            return;
-                        }
-                    } else {
-                        List<NeutronSecurityRule> secRules = secGroup.getSecurityRules();
-                        if (secRules != null) {
-                            for (NeutronSecurityRule secRule : secRules) {
-                                secRuleAware.addNeutronSecurityRule(secRule, rwTx);
-                            }
-                        }
-                    }
+            FixedIps portIpWithSubnet = potentialPortIpWithSubnet.get();
+            ContextId routerL3Context = new ContextId(port.getDeviceId());
+            ReadWriteTransaction rwTx = dataProvider.newReadWriteTransaction();
+
+            AddressEndpointKey addrEpKey = new AddressEndpointKey(port.getMacAddress().getValue(),
+                MacAddressType.class, new ContextId(port.getNetworkId().getValue()), MappingUtils.L2_BRDIGE_DOMAIN);
+            UniqueId portId = new UniqueId(port.getUuid().getValue());
+            addBaseEndpointMappings(addrEpKey, portId, rwTx);
+
+            // Add Qrouter and VPProuter port as Endpoint
+            if (port.getAugmentation(PortBindingExtension.class) != null &&
+                PortUtils.DEVICE_VIF_TYPE.equals(port.getAugmentation(PortBindingExtension.class).getVifType())) {
+                LOG.trace("Port is QRouter port: {}", port.getUuid().getValue());
+                Optional<FixedIps> firstFixedIps = PortUtils.resolveFirstFixedIps(port);
+                if (!firstFixedIps.isPresent()) {
+                    LOG.warn("QRouter port does not have an IP address. {}", port);
+                    return;
                 }
+
+                FixedIps ipWithSubnet = firstFixedIps.get();
+                NetworkDomainId networkContainment = new NetworkDomainId(ipWithSubnet.getSubnetId().getValue());
+                List<EndpointGroupId> epgsFromSecGroups = resolveEpgIdsFromSecGroups(port.getSecurityGroups());
+                epgsFromSecGroups.add(NetworkService.EPG_ID);
+
+                // BUILD BASE ENDPOINT
+                AddressEndpointRegBuilder l2BaseEp = createBasicMacAddrEpInputBuilder(port, networkContainment,
+                    epgsFromSecGroups);
+                AddressEndpointRegBuilder l3BaseEp = createBasicL3AddrEpInputBuilder(port, networkContainment,
+                    epgsFromSecGroups, neutron);
+                setParentChildRelationshipForEndpoints(l3BaseEp, l2BaseEp);
+
+                // BUILD ENDPOINT
+                org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.RegisterEndpointInputBuilder
+                    epInBuilder =
+                    createEndpointRegFromPort(
+                        port, ipWithSubnet, networkContainment, epgsFromSecGroups, neutron);
+                registerBaseEndpointAndStoreMapping(
+                    ImmutableList.of(l2BaseEp.build(), l3BaseEp.build()), port, rwTx, addBaseEpMapping);
+                registerEndpointAndStoreMapping(epInBuilder.build(), port, rwTx);
             }
-        }
-        boolean isNeutronPortCreated = addNeutronPort(port, rwTx, epService);
-        if (!isNeutronPortCreated) {
-            rwTx.cancel();
-            return;
-        }
 
-        DataStoreHelper.submitToDs(rwTx);
-    }
+            // change L3Context for all EPs with same subnet as router port
+            changeL3ContextForEpsInSubnet(portIpWithSubnet.getSubnetId(), neutron);
+            // set L3Context as parent for bridge domain which is parent of subnet
+            TenantId tenantId = new TenantId(port.getTenantId().getValue());
+            Optional<Subnet> potentialRouterPortSubnet = SubnetUtils.findSubnet(portIpWithSubnet.getSubnetId(), neutron.getSubnets());
+            if (!potentialRouterPortSubnet.isPresent()) {
+                LOG.warn("Illegal state - router interface port is in subnet which does not exist. {}",
+                        port);
+                return;
+            }
+            Subnet routerPortSubnet = potentialRouterPortSubnet.get();
+            ContextId l2BdId = new ContextId(routerPortSubnet.getNetworkId().getValue());
+            ForwardingContext l2Bd = new ForwardingContextBuilder().setContextId(l2BdId)
+                .setContextType(MappingUtils.L2_BRDIGE_DOMAIN)
+                .setParent(MappingUtils.createParent(routerL3Context, MappingUtils.L3_CONTEXT))
+                .build();
+            rwTx.merge(LogicalDatastoreType.CONFIGURATION, L2L3IidFactory.l2BridgeDomainIid(tenantId, l2BdId), l2Bd, true);
+            // set virtual router IP for subnet
+            NetworkDomain subnetDomain = NeutronSubnetAware.createSubnet(
+                    routerPortSubnet, portIpWithSubnet.getIpAddress());
+            rwTx.merge(LogicalDatastoreType.CONFIGURATION, L2L3IidFactory.subnetIid(tenantId, subnetDomain.getNetworkDomainId()), subnetDomain);
 
-    public static boolean addNeutronPort(NeutronPort port, ReadWriteTransaction rwTx, EndpointService epService) {
-        TenantId tenantId = new TenantId(Utils.normalizeUuid(port.getTenantID()));
-        L2FloodDomainId l2FdId = new L2FloodDomainId(port.getNetworkUUID());
-        ForwardingCtx fwCtx = MappingUtils.createForwardingContext(tenantId, l2FdId, rwTx);
-        boolean isFwCtxValid = validateForwardingCtx(fwCtx);
-        if (!isFwCtxValid) {
-            return false;
-        }
-        EndpointKey epKey = new EndpointKey(fwCtx.getL2BridgeDomain().getId(), new MacAddress(port.getMacAddress()));
-        addNeutronGbpMapping(port, epKey, rwTx);
-
-        try {
-            RegisterEndpointInput registerEpRpcInput = createRegisterEndpointInput(port, fwCtx);
-            RpcResult<Void> rpcResult = epService.registerEndpoint(registerEpRpcInput).get();
-            if (!rpcResult.isSuccessful()) {
-                LOG.warn("Illegal state - RPC registerEndpoint failed. Input of RPC: {}", registerEpRpcInput);
-                return false;
+            // does the same for tenant forwarding domains
+            processTenantForwarding(routerPortSubnet, routerL3Context, portIpWithSubnet, tenantId, rwTx);
+
+            DataStoreHelper.submitToDs(rwTx);
+        } else if (PortUtils.isDhcpPort(port)) {
+            // process as normal port but put it to DHCP group
+            LOG.trace("Port is DHCP port: {}", port.getUuid().getValue());
+            Optional<FixedIps> firstFixedIps = PortUtils.resolveFirstFixedIps(port);
+            if (!firstFixedIps.isPresent()) {
+                LOG.warn("DHCP port does not have an IP address. {}", port);
+                return;
             }
-        } catch (InterruptedException | ExecutionException e) {
-            LOG.error("addNeutronPort failed. {}", port, e);
-            return false;
+            FixedIps ipWithSubnet = firstFixedIps.get();
+            NetworkDomainId networkContainment = new NetworkDomainId(ipWithSubnet.getSubnetId().getValue());
+            List<EndpointGroupId> epgsFromSecGroups = resolveEpgIdsFromSecGroups(port.getSecurityGroups());
+            epgsFromSecGroups.add(NetworkService.EPG_ID);
+
+            // BUILD BASE ENDPOINT
+            AddressEndpointRegBuilder l2BaseEp = createBasicMacAddrEpInputBuilder(port, networkContainment,
+                    epgsFromSecGroups);
+            AddressEndpointRegBuilder l3BaseEp = createBasicL3AddrEpInputBuilder(port, networkContainment,
+                    epgsFromSecGroups, neutron);
+            setParentChildRelationshipForEndpoints(l3BaseEp, l2BaseEp);
+
+            // BUILD ENDPOINT
+            org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.RegisterEndpointInputBuilder epInBuilder = createEndpointRegFromPort(
+                    port, ipWithSubnet, networkContainment, epgsFromSecGroups, neutron);
+
+            ReadWriteTransaction rwTx = dataProvider.newReadWriteTransaction();
+            registerBaseEndpointAndStoreMapping(
+                    ImmutableList.of(l2BaseEp.build(), l3BaseEp.build()), port, rwTx, addBaseEpMapping);
+            registerEndpointAndStoreMapping(epInBuilder.build(), port, rwTx);
+            DataStoreHelper.submitToDs(rwTx);
+        } else if (PortUtils.isNormalPort(port)) {
+            LOG.trace("Port is normal port: {}", port.getUuid().getValue());
+            org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.RegisterEndpointInputBuilder epInBuilder = null;
+            AddressEndpointRegBuilder l2BaseEp;
+            AddressEndpointRegBuilder l3BaseEp = null;
+            Optional<FixedIps> firstFixedIps = PortUtils.resolveFirstFixedIps(port);
+            List<EndpointGroupId> epgsFromSecGroups = resolveEpgIdsFromSecGroups(port.getSecurityGroups());
+            epgsFromSecGroups.add(NetworkClient.EPG_ID);
+            if (firstFixedIps.isPresent()) {
+                // endpoint has only one network containment therefore only first IP is used
+                FixedIps ipWithSubnet = firstFixedIps.get();
+                NetworkDomainId containment = new NetworkDomainId(ipWithSubnet.getSubnetId().getValue());
+                epInBuilder = createEndpointRegFromPort(port, ipWithSubnet, containment, epgsFromSecGroups, neutron);
+                l2BaseEp = createBasicMacAddrEpInputBuilder(port,
+                        containment, epgsFromSecGroups);
+                l3BaseEp = createBasicL3AddrEpInputBuilder(port, containment, epgsFromSecGroups, neutron);
+                setParentChildRelationshipForEndpoints(l3BaseEp, l2BaseEp);
+            } else {
+                NetworkDomainId containment = new NetworkDomainId(port.getNetworkId().getValue());
+                epInBuilder = createEndpointRegFromPort(port, null, containment, epgsFromSecGroups, neutron);
+                l2BaseEp = createBasicMacAddrEpInputBuilder(port, containment, epgsFromSecGroups);
+            }
+            List<AddressEndpointReg> baseEpRegs = new ArrayList<>();
+            baseEpRegs.add(l2BaseEp.build());
+            if (l3BaseEp != null) {
+                baseEpRegs.add(l3BaseEp.build());
+            }
+            ReadWriteTransaction rwTx = dataProvider.newReadWriteTransaction();
+            registerBaseEndpointAndStoreMapping(baseEpRegs, port, rwTx, addBaseEpMapping);
+            registerEndpointAndStoreMapping(epInBuilder.build(), port, rwTx);
+            DataStoreHelper.submitToDs(rwTx);
+        } else if (PortUtils.isRouterGatewayPort(port)) {
+            // do nothing because actual trigger is attaching of port to router
+            LOG.trace("Port is router gateway port: {}", port.getUuid().getValue());
+        } else if (PortUtils.isFloatingIpPort(port)) {
+            // do nothing because trigger is floating IP
+            LOG.trace("Port is floating ip: {}", port.getUuid().getValue());
+        } else {
+            LOG.warn("Unknown port: {}", port);
         }
-        return true;
     }
 
-    public static boolean addL3EndpointForExternalGateway(TenantId tenantId, L3ContextId l3ContextId,
-            IpAddress ipAddress, NetworkDomainId networkContainment, ReadWriteTransaction rwTx) {
-
-        EndpointL3Key epL3Key = new EndpointL3Key(ipAddress, l3ContextId);
-        addNeutronExtGwGbpMapping(epL3Key, rwTx);
-        List<EndpointGroupId> epgIds = new ArrayList<>();
-        // each EP has to be in EPG ANY, except dhcp and router
-        epgIds.add(MappingUtils.EPG_EXTERNAL_ID);
-        epgIds.add(Router.EPG_ID);
-        EndpointL3 epL3 = createL3Endpoint(tenantId, epL3Key, epgIds, networkContainment);
-        InstanceIdentifier<EndpointL3> iid_l3 = IidFactory.l3EndpointIid(l3ContextId, ipAddress);
-        rwTx.put(LogicalDatastoreType.OPERATIONAL, iid_l3, epL3, true);
-        return true;
+    private void setParentChildRelationshipForEndpoints(AddressEndpointRegBuilder parentEp,
+            AddressEndpointRegBuilder childEp) {
+        childEp.setParentEndpointChoice(new ParentEndpointCaseBuilder().setParentEndpoint(
+                ImmutableList.<ParentEndpoint>of(createParentEndpoint(parentEp))).build());
+        parentEp.setChildEndpoint(ImmutableList.<ChildEndpoint>of(createChildEndpoint(childEp)));
     }
 
-    private static void addNeutronExtGwGbpMapping(EndpointL3Key epL3Key, ReadWriteTransaction rwTx) {
-            ExternalGatewayAsL3Endpoint externalGatewayL3Endpoint = MappingFactory.createExternalGatewayByL3Endpoint(epL3Key);
-            rwTx.put(LogicalDatastoreType.OPERATIONAL, NeutronGbpIidFactory.externalGatewayAsL3Endpoint(epL3Key.getL3Context(), epL3Key.getIpAddress()),
-                    externalGatewayL3Endpoint, true);
+    @Deprecated
+    private void processTenantForwarding(Subnet routerPortSubnet, ContextId routerL3Context, FixedIps portIpWithSubnet,
+            TenantId tenantId, ReadWriteTransaction rwTx) {
+        L2BridgeDomainId l2BdId = new L2BridgeDomainId(routerPortSubnet.getNetworkId().getValue());
+        L2BridgeDomain l2Bd = new L2BridgeDomainBuilder().setId(l2BdId).setParent(new L3ContextId(routerL3Context)).build();
+        rwTx.merge(LogicalDatastoreType.CONFIGURATION, IidFactory.l2BridgeDomainIid(tenantId, l2BdId), l2Bd, true);
+        // set virtual router IP for subnet
+        org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.forwarding.context.Subnet subnet = NeutronSubnetAware.createTenantSubnet(
+                routerPortSubnet, portIpWithSubnet.getIpAddress());
+        rwTx.merge(LogicalDatastoreType.CONFIGURATION, IidFactory.subnetIid(tenantId, subnet.getId()), subnet);
     }
 
-    private static void addNeutronGbpMapping(NeutronPort port, EndpointKey epKey, ReadWriteTransaction rwTx) {
-        UniqueId portId = new UniqueId(port.getID());
-        if (isRouterInterfacePort(port)) {
-            LOG.trace("Adding RouterInterfacePort-Endpoint mapping for port {} and endpoint {}", port.getID(), epKey);
-            EndpointByRouterInterfacePort endpointByPort = MappingFactory.createEndpointByRouterInterfacePort(epKey,
-                    portId);
-            rwTx.put(LogicalDatastoreType.OPERATIONAL, NeutronGbpIidFactory.endpointByRouterInterfacePortIid(portId),
-                    endpointByPort, true);
-            RouterInterfacePortByEndpoint portByEndpoint = MappingFactory.createRouterInterfacePortByEndpoint(portId,
-                    epKey);
-            rwTx.put(LogicalDatastoreType.OPERATIONAL,
-                    NeutronGbpIidFactory.routerInterfacePortByEndpointIid(epKey.getL2Context(), epKey.getMacAddress()),
-                    portByEndpoint, true);
-        } else if (isRouterGatewayPort(port)) {
-            LOG.trace("Adding RouterGatewayPort-Endpoint mapping for port {} and endpoint {}", port.getID(), epKey);
-            EndpointByRouterGatewayPort endpointByPort = MappingFactory.createEndpointByRouterGatewayPort(epKey, portId);
-            rwTx.put(LogicalDatastoreType.OPERATIONAL, NeutronGbpIidFactory.endpointByRouterGatewayPortIid(portId),
-                    endpointByPort, true);
-            RouterGatewayPortByEndpoint portByEndpoint = MappingFactory.createRouterGatewayPortByEndpoint(portId, epKey);
-            rwTx.put(LogicalDatastoreType.OPERATIONAL,
-                    NeutronGbpIidFactory.routerGatewayPortByEndpointIid(epKey.getL2Context(), epKey.getMacAddress()),
-                    portByEndpoint, true);
-        } else if (isFloatingIpPort(port)) {
-            LOG.trace("Adding FloatingIpPort-Endpoint mapping for port {} and endpoint {}", port.getID(), epKey);
-            EndpointByFloatingIpPort endpointByPort = MappingFactory.createEndpointByFloatingIpPort(epKey, portId);
-            rwTx.put(LogicalDatastoreType.OPERATIONAL, NeutronGbpIidFactory.endpointByFloatingIpPortIid(portId),
-                    endpointByPort, true);
-            FloatingIpPortByEndpoint portByEndpoint = MappingFactory.createFloatingIpPortByEndpoint(portId, epKey);
-            rwTx.put(LogicalDatastoreType.OPERATIONAL,
-                    NeutronGbpIidFactory.floatingIpPortByEndpointIid(epKey.getL2Context(), epKey.getMacAddress()),
-                    portByEndpoint, true);
-        } else {
-            LOG.trace("Adding Port-Endpoint mapping for port {} (device owner {}) and endpoint {}", port.getID(),
-                    port.getDeviceOwner(), epKey);
-            EndpointByPort endpointByPort = MappingFactory.createEndpointByPort(epKey, portId);
-            rwTx.put(LogicalDatastoreType.OPERATIONAL, NeutronGbpIidFactory.endpointByPortIid(portId), endpointByPort, true);
-            PortByEndpoint portByEndpoint = MappingFactory.createPortByEndpoint(portId, epKey);
-            rwTx.put(LogicalDatastoreType.OPERATIONAL,
-                    NeutronGbpIidFactory.portByEndpointIid(epKey.getL2Context(), epKey.getMacAddress()), portByEndpoint, true);
-        }
+    /**
+     * Registers endpoint from {@link Port} and method parameters.
+     * Always creates registration input for L2 endpoint.
+     * Creates registration input for L3 endpoint if fixedIps argument is not null.
+     */
+    @Deprecated
+    private org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.RegisterEndpointInputBuilder createEndpointRegFromPort(
+            Port port, FixedIps fixedIps, NetworkDomainId networkContainment, List<EndpointGroupId> endpointGroupIds, Neutron neutron) {
+        org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.RegisterEndpointInputBuilder epInBuilder = createBasicEndpointInputBuilder(
+                port).setNetworkContainment(networkContainment);
+        if (fixedIps != null) {
+            L3Address l3Address = resolveL3AddressFromPort(port, fixedIps, neutron);
+            epInBuilder.setL3Address(ImmutableList.of(l3Address));
+        }
+        epInBuilder.setEndpointGroups(endpointGroupIds);
+        return epInBuilder;
     }
 
-    public static boolean addL3PrefixEndpoint(L3ContextId l3ContextId, IpPrefix ipPrefix, IpAddress ipAddress, TenantId tenantId,
-            EndpointService epService) {
-        EndpointL3PrefixKey epL3PrefixKey = new EndpointL3PrefixKey( ipPrefix, l3ContextId);
-        EndpointL3Key epL3Key = null;
-        List<EndpointL3Key> l3Gateways = new ArrayList<>();
-        if (ipAddress != null) {
-            epL3Key = new EndpointL3Key(ipAddress, l3ContextId);
-            l3Gateways.add(epL3Key);
-        }
-        try {
-            RegisterL3PrefixEndpointInput registerL3PrefixEpRpcInput = createRegisterL3PrefixEndpointInput(epL3PrefixKey, l3Gateways,tenantId);
-
-            RpcResult<Void> rpcResult = epService.registerL3PrefixEndpoint(registerL3PrefixEpRpcInput).get();
-            if (!rpcResult.isSuccessful()) {
-                LOG.warn("Illegal state - RPC registerEndpoint failed. Input of RPC: {}", registerL3PrefixEpRpcInput);
-                return false;
+    private void changeL3ContextForEpsInSubnet(Uuid subnetUuid, Neutron neutron) {
+        Set<Port> portsInSameSubnet = PortUtils.findPortsBySubnet(subnetUuid, neutron.getPorts());
+        for (Port portInSameSubnet : portsInSameSubnet) {
+            if (PortUtils.isNormalPort(portInSameSubnet) || PortUtils.isDhcpPort(portInSameSubnet)
+                || PortUtils.isQrouterOrVppRouterPort(portInSameSubnet)) {
+                // endpoints are created only from neutron normal port or DHCP port
+                Optional<FixedIps> firstFixedIps = PortUtils.resolveFirstFixedIps(portInSameSubnet);
+                if (firstFixedIps.isPresent()) {
+                    // endpoint has only one network containment therefore only first IP is used
+                    FixedIps ipWithSubnet = firstFixedIps.get();
+                    List<EndpointGroupId> endpointGroupIds = new ArrayList<>();
+                    if (PortUtils.isDhcpPort(portInSameSubnet) || PortUtils.isQrouterOrVppRouterPort(portInSameSubnet)) {
+                        endpointGroupIds.add(NetworkService.EPG_ID);
+                    } else if (PortUtils.isNormalPort(portInSameSubnet)) {
+                        endpointGroupIds.add(NetworkClient.EPG_ID);
+                    }
+                    NetworkDomainId networkContainment = new NetworkDomainId(ipWithSubnet.getSubnetId().getValue());
+                    AddressEndpointRegBuilder l2BaseEp = createBasicMacAddrEpInputBuilder(portInSameSubnet,
+                            networkContainment, endpointGroupIds);
+                    AddressEndpointRegBuilder l3BaseEp = createBasicL3AddrEpInputBuilder(portInSameSubnet,
+                            networkContainment, endpointGroupIds, neutron);
+                    setParentChildRelationshipForEndpoints(l3BaseEp, l2BaseEp);
+                    AddressEndpointUnreg addrEpUnreg = new AddressEndpointUnregBuilder().setAddress(l3BaseEp.getAddress())
+                        .setAddressType(l3BaseEp.getAddressType())
+                        .setContextId(new ContextId(portInSameSubnet.getNetworkId().getValue()))
+                        .setContextType(l3BaseEp.getContextType())
+                        .build();
+                    epRegistrator.unregisterEndpoint(addrEpUnreg);
+                    RegisterEndpointInput regBaseEpInput = new RegisterEndpointInputBuilder()
+                        .setAddressEndpointReg(ImmutableList.of(l2BaseEp.build(), l3BaseEp.build())).build();
+                    epRegistrator.registerEndpoint(regBaseEpInput);
+
+                    modifyL3ContextForEndpoints(portInSameSubnet, ipWithSubnet, l3BaseEp.getContextId());
+                }
             }
-        } catch (InterruptedException | ExecutionException e) {
-            LOG.error("addPort - RPC invocation failed.", e);
-            return false;
         }
-        return true;
-
     }
 
-    private static boolean validateForwardingCtx(ForwardingCtx fwCtx) {
-        if (fwCtx.getL2FloodDomain() == null) {
-            LOG.warn("Illegal state - l2-flood-domain does not exist.");
-            return false;
-        }
-        if (fwCtx.getL2BridgeDomain() == null) {
-            LOG.warn("Illegal state - l2-bridge-domain does not exist.");
-            return false;
-        }
-        if (fwCtx.getL3Context() == null) {
-            LOG.warn("Illegal state - l3-context does not exist.");
-            return false;
-        }
-        return true;
+    private ChildEndpoint createChildEndpoint(AddressEndpointRegBuilder builder) {
+        return new ChildEndpointBuilder().setAddress(builder.getAddress())
+            .setAddressType(builder.getAddressType())
+            .setContextId(builder.getContextId())
+            .setContextType(builder.getContextType())
+            .build();
     }
 
-    /**
-     * @see org.opendaylight.neutron.spi.INeutronPortAware#canUpdatePort(org.opendaylight.neutron.spi.NeutronPort,
-     *      org.opendaylight.neutron.spi.NeutronPort)
-     */
-    @Override
-    public int canUpdatePort(NeutronPort delta, NeutronPort original) {
-        LOG.trace("canUpdatePort - delta: {} original: {}", delta, original);
-        if (delta.getFixedIPs() == null || delta.getFixedIPs().isEmpty()) {
-            return StatusCode.OK;
-        }
-        // TODO Li msunal this has to be rewrite when OFOverlay renderer will support l3-endpoints.
-        List<Neutron_IPs> fixedIPs = delta.getFixedIPs();
-        if (fixedIPs != null && fixedIPs.size() > 1) {
-            LOG.warn("Neutron mapper does not support multiple IPs on the same port.");
-            return StatusCode.BAD_REQUEST;
-        }
-        return StatusCode.OK;
+    private ParentEndpoint createParentEndpoint(AddressEndpointRegBuilder builder) {
+        return new ParentEndpointBuilder().setAddress(builder.getAddress())
+            .setAddressType(builder.getAddressType())
+            .setContextId(builder.getContextId())
+            .setContextType(builder.getContextType())
+            .build();
     }
 
-    /**
-     * @see org.opendaylight.neutron.spi.INeutronPortAware#neutronPortUpdated(org.opendaylight.neutron.spi.NeutronPort)
-     */
-    @Override
-    public void neutronPortUpdated(NeutronPort port) {
-        LOG.trace("neutronPortUpdated - {}", port);
-        if (isRouterInterfacePort(port)) {
-            LOG.trace("Port is router interface - {} does nothing. {} handles router iface.",
-                    NeutronPortAware.class.getSimpleName(), NeutronRouterAware.class.getSimpleName());
-            return;
-        }
-        if (isRouterGatewayPort(port)) {
-            LOG.trace("Port is router gateway - {}", port.getID());
-            return;
-        }
-        if (isFloatingIpPort(port)) {
-            LOG.trace("Port is floating ip - {}", port.getID());
-            return;
-        }
-        if (Strings.isNullOrEmpty(port.getTenantID())) {
-            LOG.trace("REMOVE ME: Tenant is null - {}", port.getID());
-            return;
-        }
-
-        ReadOnlyTransaction rTx = dataProvider.newReadOnlyTransaction();
-        TenantId tenantId = new TenantId(Utils.normalizeUuid(port.getTenantID()));
-        MacAddress macAddress = new MacAddress(port.getMacAddress());
-        L2FloodDomainId l2FdId = new L2FloodDomainId(port.getNetworkUUID());
-        ForwardingCtx fwCtx = MappingUtils.createForwardingContext(tenantId, l2FdId, rTx);
-        boolean isFwCtxValid = validateForwardingCtx(fwCtx);
-        if (!isFwCtxValid) {
-            rTx.close();
-            return;
-        }
-
-        Optional<Endpoint> potentionalEp = DataStoreHelper.readFromDs(LogicalDatastoreType.OPERATIONAL,
-                IidFactory.endpointIid(fwCtx.getL2BridgeDomain().getId(), macAddress), rTx);
-        if (!potentionalEp.isPresent()) {
-            LOG.warn("Illegal state - endpoint {} does not exist.", new EndpointKey(fwCtx.getL2BridgeDomain().getId(),
-                    macAddress));
-            rTx.close();
-            return;
-        }
+    @Deprecated
+    private void modifyL3ContextForEndpoints(Port port, FixedIps resolvedPortFixedIp, ContextId newContextId) {
+        org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.RegisterEndpointInputBuilder epInBuilder = createBasicEndpointInputBuilder(port);
+        epInBuilder.setNetworkContainment(new NetworkDomainId(resolvedPortFixedIp.getSubnetId().getValue()));
+        L3Address l3Address = new L3AddressBuilder().setL3Context(new L3ContextId(newContextId))
+            .setIpAddress(resolvedPortFixedIp.getIpAddress())
+            .build();
+        epInBuilder.setL3Address(ImmutableList.of(l3Address));
+        List<EndpointGroupId> epgsFromSecGroups = resolveEpgIdsFromSecGroups(port.getSecurityGroups());
+        epgsFromSecGroups.add(NetworkClient.EPG_ID);
+        epInBuilder.setEndpointGroups(epgsFromSecGroups);
+        epRegistrator.registerEndpoint(epInBuilder.build());
+        // unregister L3EP
+        L3ContextId oldL3Context = new L3ContextId(port.getNetworkId().getValue());
+        L3 l3 = new L3Builder().setL3Context(oldL3Context).setIpAddress(resolvedPortFixedIp.getIpAddress()).build();
+        org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.UnregisterEndpointInput epUnreg = new org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.UnregisterEndpointInputBuilder().setL3(
+                ImmutableList.of(l3))
+            .build();
+        epRegistrator.unregisterEndpoint(epUnreg);
+    }
 
-        Endpoint ep = potentionalEp.get();
-        if (isEpIpDifferentThanPortFixedIp(ep, port) || isEpgDifferentThanSecGrp(ep, port)) {
-            UnregisterEndpointInput unregisterEpRpcInput = createUnregisterEndpointInput(ep);
-            RegisterEndpointInput registerEpRpcInput = createRegisterEndpointInput(port, fwCtx);
-            try {
-                RpcResult<Void> rpcResult = epService.unregisterEndpoint(unregisterEpRpcInput).get();
-                if (!rpcResult.isSuccessful()) {
-                    LOG.warn("Illegal state - RPC unregisterEndpoint failed. Input of RPC: {}", unregisterEpRpcInput);
-                    rTx.close();
-                    return;
-                }
-                rpcResult = epService.registerEndpoint(registerEpRpcInput).get();
-                if (!rpcResult.isSuccessful()) {
-                    LOG.warn("Illegal state - RPC registerEndpoint failed. Input of RPC: {}", registerEpRpcInput);
-                    rTx.close();
-                    return;
-                }
-            } catch (InterruptedException | ExecutionException e) {
-                LOG.error("addPort - RPC invocation failed.", e);
-                rTx.close();
-                return;
-            }
-        }
-        rTx.close();
+    private AddressEndpointRegBuilder createBasicMacAddrEpInputBuilder(Port port,
+            NetworkDomainId networkContainment, @Nullable List<EndpointGroupId> endpointGroupsToAdd) {
+        AddressEndpointRegBuilder addrEpbuilder = new AddressEndpointRegBuilder().setAddressType(MacAddressType.class)
+            .setAddress(port.getMacAddress().getValue())
+            .setAddressType(MacAddressType.class)
+            .setContextType(MappingUtils.L2_BRDIGE_DOMAIN)
+            .setContextId(new ContextId(port.getNetworkId().getValue()))
+            .setTenant(new TenantId(port.getTenantId().getValue()))
+            .setTimestamp(System.currentTimeMillis());
+        List<EndpointGroupId> epgs = concatEndpointGroups(port.getSecurityGroups(), endpointGroupsToAdd);
+        addrEpbuilder.setEndpointGroup(epgs);
+        if (networkContainment != null) {
+            addrEpbuilder.setNetworkContainment(new NetworkContainmentBuilder().setContainment(
+                    new NetworkDomainContainmentBuilder().setNetworkDomainId(networkContainment)
+                        .setNetworkDomainType(MappingUtils.SUBNET)
+                        .build()).build());
+        }
+        return addrEpbuilder;
     }
 
-    private boolean isEpIpDifferentThanPortFixedIp(Endpoint ep, NeutronPort port) {
-        List<L3Address> l3Addresses = ep.getL3Address();
-        List<Neutron_IPs> fixedIPs = port.getFixedIPs();
-        if ((l3Addresses == null || l3Addresses.isEmpty()) && (fixedIPs == null || fixedIPs.isEmpty())) {
-            return false;
-        }
-        if (l3Addresses != null && !l3Addresses.isEmpty() && fixedIPs != null && !fixedIPs.isEmpty()) {
-            if (fixedIPs.get(0).getIpAddress().equals(Utils.getStringIpAddress(l3Addresses.get(0).getIpAddress()))) {
-                return false;
-            }
-        }
-        return true;
+    private AddressEndpointRegBuilder createBasicL3AddrEpInputBuilder(Port port, NetworkDomainId networkContainment,
+            @Nullable List<EndpointGroupId> endpointGroupsToAdd, Neutron neutron) {
+        Optional<FixedIps> firstFixedIps = PortUtils.resolveFirstFixedIps(port);
+        if (!firstFixedIps.isPresent()) {
+            throw new IllegalStateException("Failed to resolve FixedIps for port " + port.getKey()
+                    + ". Cannot register L3 Address endpoint.");
+        }
+        ContextId resolveL3ContextForPort = resolveL3ContextForPort(port, port.getFixedIps().get(0), neutron);
+
+        AddressEndpointRegBuilder addrEpbuilder = new AddressEndpointRegBuilder().setAddressType(MacAddressType.class)
+            .setAddress(MappingUtils.ipAddressToStringIpPrefix(firstFixedIps.get().getIpAddress()))
+            .setAddressType(IpPrefixType.class)
+            .setContextType(MappingUtils.L3_CONTEXT)
+            .setContextId(resolveL3ContextForPort)
+            .setTenant(new TenantId(port.getTenantId().getValue()))
+            .setTimestamp(System.currentTimeMillis());
+        List<EndpointGroupId> epgs = concatEndpointGroups(port.getSecurityGroups(), endpointGroupsToAdd);
+        addrEpbuilder.setEndpointGroup(epgs);
+        if (networkContainment != null) {
+            addrEpbuilder.setNetworkContainment(new NetworkContainmentBuilder().setContainment(
+                    new NetworkDomainContainmentBuilder().setNetworkDomainId(networkContainment)
+                        .setNetworkDomainType(MappingUtils.SUBNET)
+                        .build()).build());
+        }
+        return addrEpbuilder;
     }
 
-    private boolean isEpgDifferentThanSecGrp(Endpoint ep, NeutronPort port) {
-        List<EndpointGroupId> epgIds = ep.getEndpointGroups();
-        List<NeutronSecurityGroup> secGroups = port.getSecurityGroups();
-        if ((epgIds == null || epgIds.isEmpty()) && (secGroups == null || secGroups.isEmpty())) {
-            return false;
-        }
-        if (epgIds != null && !epgIds.isEmpty() && secGroups != null && !secGroups.isEmpty()) {
-            if (epgIds.size() != secGroups.size()) {
-                return true;
-            }
-            Collection<EndpointGroupId> epgIdsFromSecGroups = Collections2.transform(secGroups,
-                    new Function<NeutronSecurityGroup, EndpointGroupId>() {
-
-                        @Override
-                        public EndpointGroupId apply(NeutronSecurityGroup input) {
-                            return new EndpointGroupId(input.getSecurityGroupUUID());
-                        }
-                    });
-            // order independent equals
-            Set<EndpointGroupId> one = new HashSet<>(epgIds);
-            Set<EndpointGroupId> two = new HashSet<>(epgIdsFromSecGroups);
-            if (one.equals(two)) {
-                return false;
+    private List<EndpointGroupId> concatEndpointGroups(List<Uuid> securityGroups,
+            @Nullable List<EndpointGroupId> endpointGroupsToAdd) {
+        List<EndpointGroupId> epgs = new ArrayList<>();
+        if (securityGroups != null) {
+            for (Uuid sgId : securityGroups) {
+                epgs.add(new EndpointGroupId(sgId.getValue()));
             }
         }
-        return true;
+        if (endpointGroupsToAdd != null) {
+            epgs.addAll(endpointGroupsToAdd);
+        }
+        return epgs;
     }
 
-    /**
-     * @see org.opendaylight.neutron.spi.INeutronPortAware#canDeletePort(org.opendaylight.neutron.spi.NeutronPort)
-     */
-    @Override
-    public int canDeletePort(NeutronPort port) {
-        LOG.trace("canDeletePort - {}", port);
-        // nothing to consider
-        return StatusCode.OK;
+    @Deprecated
+    private static org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.RegisterEndpointInputBuilder createBasicEndpointInputBuilder(
+            Port port) {
+        return new org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.RegisterEndpointInputBuilder().setL2Context(
+                new L2BridgeDomainId(port.getNetworkId().getValue()))
+            .setMacAddress(new MacAddress(port.getMacAddress().getValue()))
+            .setTenant(new TenantId(port.getTenantId().getValue()))
+            .setTimestamp(System.currentTimeMillis());
     }
 
-    /**
-     * @see org.opendaylight.neutron.spi.INeutronPortAware#neutronPortDeleted(org.opendaylight.neutron.spi.NeutronPort)
-     */
-    @Override
-    public void neutronPortDeleted(NeutronPort port) {
-        LOG.trace("neutronPortDeleted - {}", port);
-        if (isRouterInterfacePort(port)) {
-            LOG.trace("Port is router interface - {} does nothing. {} handles router iface.",
-                    NeutronPortAware.class.getSimpleName(), NeutronRouterAware.class.getSimpleName());
-            return;
-        }
-        if (isRouterGatewayPort(port)) {
-            LOG.trace("Port is router gateway - {} does nothing. {} handles router iface.",
-                    NeutronPortAware.class.getSimpleName(), NeutronRouterAware.class.getSimpleName());
-            return;
-        }
-        if (isFloatingIpPort(port)) {
-            LOG.trace("Port is floating ip - {} device id - {}", port.getID(), port.getDeviceID());
-            floatingIpPortByDeviceId.remove(port.getDeviceID());
+    private static List<EndpointGroupId> resolveEpgIdsFromSecGroups(@Nullable List<Uuid> securityGroups) {
+        List<EndpointGroupId> epgIds = new ArrayList<>();
+        if ((securityGroups == null || securityGroups.isEmpty())) {
+            return epgIds;
         }
-        ReadWriteTransaction rwTx = dataProvider.newReadWriteTransaction();
-        TenantId tenantId = new TenantId(Utils.normalizeUuid(port.getTenantID()));
-        L2FloodDomainId l2FdId = new L2FloodDomainId(port.getNetworkUUID());
-        ForwardingCtx fwCtx = MappingUtils.createForwardingContext(tenantId, l2FdId, rwTx);
-        boolean isFwCtxValid = validateForwardingCtx(fwCtx);
-        if (!isFwCtxValid) {
-            rwTx.cancel();
-            return;
+        for (Uuid secGrp : securityGroups) {
+            epgIds.add(new EndpointGroupId(secGrp.getValue()));
         }
+        return epgIds;
+    }
 
-        UnregisterEndpointInput unregisterEpRpcInput = createUnregisterEndpointInput(port, fwCtx);
-        boolean isEndpointUnregistered = false;
-        try {
-            isEndpointUnregistered = epService.unregisterEndpoint(unregisterEpRpcInput).get().isSuccessful();
-        } catch (InterruptedException | ExecutionException e) {
-            LOG.error("unregisterEndpoint - RPC invocation failed.", e);
-        }
-        if (isEndpointUnregistered) {
-            EndpointKey epKey = new EndpointKey(fwCtx.getL2BridgeDomain().getId(), new MacAddress(port.getMacAddress()));
-            deleteNeutronGbpMapping(port, epKey, rwTx);
-            DataStoreHelper.submitToDs(rwTx);
-        } else {
-            LOG.warn("Illegal state - RPC unregisterEndpoint failed. Input of RPC: {}", unregisterEpRpcInput);
-            rwTx.cancel();
+    @Deprecated
+    private void registerEndpointAndStoreMapping(
+            org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.RegisterEndpointInput regEpInput,
+            Port port, ReadWriteTransaction rwTx) {
+        boolean isRegisteredEndpoint = epRegistrator.registerEndpoint(regEpInput);
+        if (!isRegisteredEndpoint) {
+            LOG.error("Failed to register an endpoint: {}", regEpInput);
+            return;
         }
+        UniqueId portId = new UniqueId(port.getUuid().getValue());
+        EndpointKey epKey = new EndpointKey(new L2BridgeDomainId(port.getNetworkId().getValue()), new MacAddress(
+                port.getMacAddress().getValue()));
+        LOG.trace("Adding Port-Endpoint mapping for port {} (device owner {}) and endpoint {}", port.getUuid()
+            .getValue(), port.getDeviceOwner(), epKey);
+        EndpointByPort endpointByPort = MappingFactory.createEndpointByPort(epKey, portId);
+        rwTx.put(LogicalDatastoreType.OPERATIONAL, NeutronGbpIidFactory.endpointByPortIid(portId), endpointByPort, true);
+        PortByEndpoint portByEndpoint = MappingFactory.createPortByEndpoint(portId, epKey);
+        rwTx.put(LogicalDatastoreType.OPERATIONAL,
+                NeutronGbpIidFactory.portByEndpointIid(epKey.getL2Context(), epKey.getMacAddress()), portByEndpoint,
+                true);
     }
 
-    private static void deleteNeutronGbpMapping(NeutronPort port, EndpointKey epKey, ReadWriteTransaction rwTx) {
-        UniqueId portId = new UniqueId(port.getID());
-        if (isRouterInterfacePort(port)) {
-            LOG.trace("Adding RouterInterfacePort-Endpoint mapping for port {} and endpoint {}", port.getID(), epKey);
+    @Deprecated
+    private void unregisterEndpointAndRemoveMapping(
+            org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.UnregisterEndpointInput unregEpInput,
+            Port port, ReadWriteTransaction rwTx) {
+        boolean isUnregisteredEndpoint = epRegistrator.unregisterEndpoint(unregEpInput);
+        if (isUnregisteredEndpoint) {
+            UniqueId portId = new UniqueId(port.getUuid().getValue());
+            EndpointKey epKey = new EndpointKey(new L2BridgeDomainId(port.getNetworkId().getValue()), new MacAddress(
+                    port.getMacAddress().getValue()));
+            LOG.trace("Removing Port-Endpoint mapping for port {} (device owner {}) and endpoint {}", port.getUuid()
+                .getValue(), port.getDeviceOwner(), epKey);
             DataStoreHelper.removeIfExists(LogicalDatastoreType.OPERATIONAL,
-                    NeutronGbpIidFactory.endpointByRouterInterfacePortIid(portId), rwTx);
-            DataStoreHelper.removeIfExists(LogicalDatastoreType.OPERATIONAL,
-                    NeutronGbpIidFactory.routerInterfacePortByEndpointIid(epKey.getL2Context(), epKey.getMacAddress()), rwTx);
-        } else if (isRouterGatewayPort(port)) {
-            LOG.trace("Adding RouterGatewayPort-Endpoint mapping for port {} and endpoint {}", port.getID(), epKey);
-            DataStoreHelper.removeIfExists(LogicalDatastoreType.OPERATIONAL,
-                    NeutronGbpIidFactory.endpointByRouterGatewayPortIid(portId), rwTx);
-            DataStoreHelper.removeIfExists(LogicalDatastoreType.OPERATIONAL,
-                    NeutronGbpIidFactory.routerGatewayPortByEndpointIid(epKey.getL2Context(), epKey.getMacAddress()), rwTx);
-        } else if (isFloatingIpPort(port)) {
-            LOG.trace("Adding FloatingIpPort-Endpoint mapping for port {} and endpoint {}", port.getID(), epKey);
-            DataStoreHelper.removeIfExists(LogicalDatastoreType.OPERATIONAL,
-                    NeutronGbpIidFactory.endpointByFloatingIpPortIid(portId), rwTx);
-            DataStoreHelper.removeIfExists(LogicalDatastoreType.OPERATIONAL,
-                    NeutronGbpIidFactory.floatingIpPortByEndpointIid(epKey.getL2Context(), epKey.getMacAddress()), rwTx);
-        } else {
-            LOG.trace("Adding Port-Endpoint mapping for port {} (device owner {}) and endpoint {}", port.getID(),
-                    port.getDeviceOwner(), epKey);
-            DataStoreHelper.removeIfExists(LogicalDatastoreType.OPERATIONAL, NeutronGbpIidFactory.endpointByPortIid(portId), rwTx);
+                    NeutronGbpIidFactory.endpointByPortIid(portId), rwTx);
             DataStoreHelper.removeIfExists(LogicalDatastoreType.OPERATIONAL,
                     NeutronGbpIidFactory.portByEndpointIid(epKey.getL2Context(), epKey.getMacAddress()), rwTx);
         }
     }
 
-    private static RegisterL3PrefixEndpointInput createRegisterL3PrefixEndpointInput(EndpointL3PrefixKey key, List<EndpointL3Key> endpointL3Keys, TenantId tenantId) {
-        List<EndpointGroupId> epgIds = new ArrayList<>();
-        List<EndpointL3Gateways> l3Gateways = new ArrayList<EndpointL3Gateways>();
-        for (EndpointL3Key epL3Key : endpointL3Keys) {
-            EndpointL3Gateways l3Gateway = new EndpointL3GatewaysBuilder().setIpAddress(epL3Key.getIpAddress())
-                .setL3Context(epL3Key.getL3Context())
-                .build();
-            l3Gateways.add(l3Gateway);
+    private void registerBaseEndpointAndStoreMapping(List<AddressEndpointReg> addrEpRegs, Port port,
+            WriteTransaction wTx, boolean addBaseEpMappings) {
+        RegisterEndpointInput regBaseEpInput = new RegisterEndpointInputBuilder().setAddressEndpointReg(addrEpRegs)
+            .build();
+
+        boolean isRegisteredBaseEndpoint = epRegistrator.registerEndpoint(regBaseEpInput);
+        if (!isRegisteredBaseEndpoint) {
+            LOG.error("Failed to register an address endpoint: {}", addrEpRegs);
+            return;
+        }
+        for (AddressEndpointReg addrEpReg : addrEpRegs) {
+            if (MappingUtils.L2_BRDIGE_DOMAIN.equals(addrEpReg.getContextType()) && addBaseEpMappings) {
+                UniqueId portId = new UniqueId(port.getUuid().getValue());
+                LOG.trace("Adding Port-BaseEndpoint mapping for port {} (device owner {}) and endpoint {}",
+                        port.getUuid());
+                AddressEndpointKey addrEpKey = new AddressEndpointKey(addrEpReg.getAddress(),
+                        addrEpReg.getAddressType(), addrEpReg.getContextId(), addrEpReg.getContextType());
+                addBaseEndpointMappings(addrEpKey, portId, wTx);
+            }
         }
-        RegisterL3PrefixEndpointInputBuilder inputBuilder = new RegisterL3PrefixEndpointInputBuilder()
-                                                .setL3Context(key.getL3Context())
-                                                .setIpPrefix(key.getIpPrefix())
-                                                .setEndpointGroups(epgIds)
-                                                .setTenant(tenantId)
-                                                .setEndpointL3Gateways(l3Gateways)
-                                                .setTimestamp(System.currentTimeMillis());
-        return inputBuilder.build();
     }
 
-    private static EndpointL3 createL3Endpoint(TenantId tenantId, EndpointL3Key epL3Key,
-            List<EndpointGroupId> epgIds, NetworkDomainId containment) {
-
-        EndpointL3Builder epL3Builder = new EndpointL3Builder()
-        .setTenant(tenantId)
-        .setNetworkContainment(containment)
-        .setIpAddress(epL3Key.getIpAddress())
-        .setL3Context(epL3Key.getL3Context())
-        .setEndpointGroups(epgIds)
-        .setTimestamp(System.currentTimeMillis());
-
-        return epL3Builder.build();
+    private void addBaseEndpointMappings(AddressEndpointKey addrEpKey, UniqueId portId, WriteTransaction wTx) {
+        BaseEndpointByPort baseEndpointByPort = MappingFactory.createBaseEndpointByPort(addrEpKey, portId);
+        wTx.put(LogicalDatastoreType.OPERATIONAL, NeutronGbpIidFactory.baseEndpointByPortIid(portId),
+                baseEndpointByPort, true);
+        PortByBaseEndpoint portByBaseEndpoint = MappingFactory.createPortByBaseEndpoint(portId, addrEpKey);
+        wTx.put(LogicalDatastoreType.OPERATIONAL,
+                NeutronGbpIidFactory.portByBaseEndpointIid(new PortByBaseEndpointKey(
+                        portByBaseEndpoint.getKey())), portByBaseEndpoint, true);
     }
 
-    private static RegisterEndpointInput createRegisterEndpointInput(NeutronPort port, ForwardingCtx fwCtx) {
-        List<EndpointGroupId> epgIds = new ArrayList<>();
-        if (isDhcpPort(port)) {
-            epgIds.add(NetworkService.EPG_ID);
-        }
-
-        List<NeutronSecurityGroup> securityGroups = port.getSecurityGroups();
-        if ((securityGroups == null || securityGroups.isEmpty())) {
-            if (isFloatingIpPort(port)) {
-                epgIds.add(MappingUtils.EPG_EXTERNAL_ID);
-            } else if (!isDhcpPort(port)) {
-                LOG.warn(
-                        "Port {} does not contain any security group. The port should belong to 'default' security group at least.",
-                        port.getPortUUID());
+    private void unregisterEndpointAndRemoveMapping(UnregisterEndpointInput baseEpUnreg, Port port,
+            ReadWriteTransaction rwTx, boolean removeBaseEpMappings) {
+        boolean isUnregisteredBaseEndpoint = epRegistrator.unregisterEndpoint(baseEpUnreg);
+        if (isUnregisteredBaseEndpoint) {
+            UniqueId portId = new UniqueId(port.getUuid().getValue());
+            PortByBaseEndpointKey portByBaseEndpointKey = new PortByBaseEndpointKey(port.getMacAddress().getValue(),
+                    MacAddressType.class, new ContextId(port.getNetworkId().getValue()), MappingUtils.L2_BRDIGE_DOMAIN);
+            LOG.trace("Removing Port-BaseEndpoint mapping for port {} (device owner {}) and endpoint {}",
+                    port.getUuid().getValue(), port.getDeviceOwner(), portByBaseEndpointKey);
+            if (removeBaseEpMappings) {
+                removeBaseEndpointMappings(portByBaseEndpointKey, portId, rwTx);
             }
-        } else {
-            for (NeutronSecurityGroup secGrp : securityGroups) {
-                epgIds.add(new EndpointGroupId(secGrp.getSecurityGroupUUID()));
-            }
-            epgIds.add(NetworkClient.EPG_ID);
-        }
-        LocationType locationType = LocationType.Internal;
-        if(isRouterGatewayPort(port)) {
-            locationType = LocationType.External;
-        }
-        RegisterEndpointInputBuilder inputBuilder = new RegisterEndpointInputBuilder().setL2Context(
-                fwCtx.getL2BridgeDomain().getId())
-            .setMacAddress(new MacAddress(port.getMacAddress()))
-            .setTenant(new TenantId(Utils.normalizeUuid(port.getTenantID())))
-            .setEndpointGroups(epgIds)
-            .addAugmentation(OfOverlayContextInput.class,
-                    new OfOverlayContextInputBuilder()
-                        .setPortName(createTapPortName(port))
-                        .setLocationType(locationType)
-                    .build())
-            .setTimestamp(System.currentTimeMillis());
-        List<Neutron_IPs> fixedIPs = port.getFixedIPs();
-        // TODO Li msunal this getting of just first IP has to be rewrite when OFOverlay renderer
-        // will support l3-endpoints. Then we will register L2 and L3 endpoints separately.
-        Neutron_IPs firstIp = MappingUtils.getFirstIp(fixedIPs);
-        if (firstIp != null) {
-            inputBuilder.setNetworkContainment(new SubnetId(firstIp.getSubnetUUID()));
-            L3Address l3Address = new L3AddressBuilder().setIpAddress(Utils.createIpAddress(firstIp.getIpAddress()))
-                .setL3Context(fwCtx.getL3Context().getId())
-                .build();
-            inputBuilder.setL3Address(ImmutableList.of(l3Address));
-        }
-        if (!Strings.isNullOrEmpty(port.getName())) {
-
         }
-        return inputBuilder.build();
     }
 
-    private static Name createTapPortName(NeutronPort port) {
-        return new Name("tap" + port.getID().substring(0, 11));
+    private void removeBaseEndpointMappings(PortByBaseEndpointKey portByBaseEndpointKey, UniqueId portId, ReadWriteTransaction rwTx) {
+        DataStoreHelper.removeIfExists(LogicalDatastoreType.OPERATIONAL,
+                NeutronGbpIidFactory.baseEndpointByPortIid(portId), rwTx);
+        DataStoreHelper.removeIfExists(LogicalDatastoreType.OPERATIONAL,
+                NeutronGbpIidFactory.portByBaseEndpointIid(portByBaseEndpointKey), rwTx);
     }
 
-    private static boolean isDhcpPort(NeutronPort port) {
-        return DEVICE_OWNER_DHCP.equals(port.getDeviceOwner());
+    @Override
+    public void onUpdated(Port oldPort, Port newPort, Neutron oldNeutron, Neutron newNeutron) {
+        LOG.trace("updated port - OLD: {}\nNEW: {}", oldPort, newPort);
+        onDeleted(oldPort, oldNeutron, newNeutron, false);
+        onCreated(newPort, newNeutron, false);
     }
 
-    private static boolean isRouterInterfacePort(NeutronPort port) {
-        return DEVICE_OWNER_ROUTER_IFACE.equals(port.getDeviceOwner());
+    @Override public void onDeleted(Port deletedItem, Neutron oldNeutron, Neutron newNeutron) {
+        onDeleted(deletedItem, oldNeutron, newNeutron, true);
     }
 
-    private static boolean isRouterGatewayPort(NeutronPort port) {
-        return DEVICE_OWNER_ROUTER_GATEWAY.equals(port.getDeviceOwner());
+    public void onDeleted(Port port, Neutron oldNeutron, Neutron newNeutron, boolean removeBaseEpMapping) {
+        LOG.trace("deleted port - {}", port);
+        if (PortUtils.isRouterInterfacePort(port)) {
+            LOG.trace("Port is router interface port: {}", port.getUuid().getValue());
+            // router interface port can have only one IP
+            Optional<FixedIps> potentialPortIpWithSubnet = PortUtils.resolveFirstFixedIps(port);
+            if (!potentialPortIpWithSubnet.isPresent()) {
+                LOG.warn("Illegal state - router interface port does not contain fixed IPs {}",
+                        port);
+                return;
+            }
+            FixedIps portIpWithSubnet = potentialPortIpWithSubnet.get();
+            L3ContextId l3Context = new L3ContextId(port.getNetworkId().getValue());
+            // change L3Context for all EPs with same subnet as router port
+            changeL3ContextForEpsInSubnet(portIpWithSubnet.getSubnetId(), newNeutron);
+            // set L3Context as parent for bridge domain which is parent of subnet
+            TenantId tenantId = new TenantId(port.getTenantId().getValue());
+            Optional<Subnet> potentialRouterPortSubnet = SubnetUtils.findSubnet(portIpWithSubnet.getSubnetId(),
+                    oldNeutron.getSubnets());
+            if (!potentialRouterPortSubnet.isPresent()) {
+                LOG.warn("Illegal state - router interface port is in subnet which does not exist. {}", port);
+                return;
+            }
+            ReadWriteTransaction rwTx = dataProvider.newReadWriteTransaction();
+            Subnet routerPortSubnet = potentialRouterPortSubnet.get();
+            modifyForwardingOnDelete(routerPortSubnet, l3Context, tenantId, rwTx);
+            ContextId l2BdId = new ContextId(routerPortSubnet.getNetworkId().getValue());
+            ForwardingContext fwdCtx = new ForwardingContextBuilder().setContextId(l2BdId)
+                .setContextType(MappingUtils.L2_BRDIGE_DOMAIN)
+                .setParent(MappingUtils.createParent(l3Context, MappingUtils.L3_CONTEXT))
+                .build();
+            rwTx.merge(LogicalDatastoreType.CONFIGURATION,
+                    L2L3IidFactory.l2BridgeDomainIid(tenantId, fwdCtx.getContextId()), fwdCtx);
+            NetworkDomain subnet = NeutronSubnetAware.createSubnet(routerPortSubnet, null);
+            rwTx.put(LogicalDatastoreType.CONFIGURATION, L2L3IidFactory.subnetIid(tenantId, subnet.getNetworkDomainId()),
+                    subnet);
+            unregisterEndpointAndRemoveMapping(createUnregisterEndpointInput(port, oldNeutron), port, rwTx);
+            unregisterEndpointAndRemoveMapping(createUnregisterBaseEndpointInput(port, oldNeutron), port, rwTx, removeBaseEpMapping);
+            DataStoreHelper.submitToDs(rwTx);
+        } else if (PortUtils.isDhcpPort(port)) {
+            LOG.trace("Port is DHCP port: {}", port.getUuid().getValue());
+            ReadWriteTransaction rwTx = dataProvider.newReadWriteTransaction();
+            unregisterEndpointAndRemoveMapping(createUnregisterEndpointInput(port, oldNeutron), port, rwTx);
+            unregisterEndpointAndRemoveMapping(createUnregisterBaseEndpointInput(port, oldNeutron), port, rwTx, removeBaseEpMapping);
+            DataStoreHelper.submitToDs(rwTx);
+        } else if (PortUtils.isNormalPort(port)) {
+            LOG.trace("Port is normal port: {}", port.getUuid().getValue());
+            ReadWriteTransaction rwTx = dataProvider.newReadWriteTransaction();
+            unregisterEndpointAndRemoveMapping(createUnregisterEndpointInput(port, oldNeutron), port, rwTx);
+            unregisterEndpointAndRemoveMapping(createUnregisterBaseEndpointInput(port, oldNeutron), port, rwTx, removeBaseEpMapping);
+            DataStoreHelper.submitToDs(rwTx);
+        } else if (PortUtils.isRouterGatewayPort(port)) {
+            // do nothing because actual trigger is detaching of port from router
+            LOG.trace("Port is router gateway port: {}", port.getUuid().getValue());
+        } else if (PortUtils.isFloatingIpPort(port)) {
+            // do nothing because trigger is floating IP
+            LOG.trace("Port is floating ip: {}", port.getUuid().getValue());
+        } else {
+            LOG.warn("Unknown port: {}", port);
+        }
     }
 
-    private static boolean isFloatingIpPort(NeutronPort port) {
-        return DEVICE_OWNER_FLOATING_IP.equals(port.getDeviceOwner());
+    @Deprecated
+    private void modifyForwardingOnDelete(Subnet routerPortSubnet, L3ContextId l3contextId, TenantId tenantId, ReadWriteTransaction rwTx) {
+        L2BridgeDomainId l2BdId = new L2BridgeDomainId(routerPortSubnet.getNetworkId().getValue());
+        L2BridgeDomain l2Bd = new L2BridgeDomainBuilder().setId(l2BdId).setParent(l3contextId).build();
+        rwTx.merge(LogicalDatastoreType.CONFIGURATION, IidFactory.l2BridgeDomainIid(tenantId, l2BdId), l2Bd);
+        // remove virtual router IP for subnet
+        org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.forwarding.context.Subnet tenantSubnet = NeutronSubnetAware.createTenantSubnet(routerPortSubnet, null);
+        rwTx.put(LogicalDatastoreType.CONFIGURATION, IidFactory.subnetIid(tenantId, tenantSubnet.getId()), tenantSubnet);
     }
 
-    private UnregisterEndpointInput createUnregisterEndpointInput(Endpoint ep) {
+    private org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.UnregisterEndpointInput createUnregisterBaseEndpointInput(
+            Port port, Neutron neutron) {
         UnregisterEndpointInputBuilder inputBuilder = new UnregisterEndpointInputBuilder();
-        L2 l2Ep = new L2Builder().setL2Context(ep.getL2Context()).setMacAddress(ep.getMacAddress()).build();
-        inputBuilder.setL2(ImmutableList.of(l2Ep));
-        // TODO Li msunal this has to be rewrite when OFOverlay renderer will support l3-endpoints.
-        // Endpoint probably will not have l3-addresses anymore, because L2 and L3 endpoints should
-        // be registered separately.
-        if (ep.getL3Address() != null && !ep.getL3Address().isEmpty()) {
-            List<L3> l3Eps = new ArrayList<>();
-            for (L3Address ip : ep.getL3Address()) {
-                l3Eps.add(new L3Builder().setL3Context(ip.getL3Context()).setIpAddress(ip.getIpAddress()).build());
-            }
-            inputBuilder.setL3(l3Eps);
-        }
+        List<AddressEndpointUnreg> list = new ArrayList<>();
+        AddressEndpointUnregBuilder addrL2EpUnregBuilder = new AddressEndpointUnregBuilder();
+        addrL2EpUnregBuilder.setAddress(port.getMacAddress().getValue())
+            .setAddressType(MacAddressType.class)
+            .setContextId(new ContextId(port.getNetworkId().getValue()))
+            .setContextType(MappingUtils.L2_BRDIGE_DOMAIN);
+        list.add(addrL2EpUnregBuilder.build());
+        Optional<FixedIps> potentialFirstIp = PortUtils.resolveFirstFixedIps(port);
+        if (potentialFirstIp.isPresent()) {
+            ContextId l3ContextId = resolveL3ContextForPort(port, potentialFirstIp.get(), neutron);
+            AddressEndpointUnregBuilder addrL3EpUnregBuilder = new AddressEndpointUnregBuilder();
+            addrL3EpUnregBuilder.setAddress(MappingUtils.ipAddressToStringIpPrefix(potentialFirstIp.get().getIpAddress()))
+                .setAddressType(IpPrefixType.class)
+                .setContextId(l3ContextId)
+                .setContextType(L3Context.class);
+            list.add(addrL3EpUnregBuilder.build());
+        }
+        inputBuilder.setAddressEndpointUnreg(list);
         return inputBuilder.build();
     }
 
-    private UnregisterEndpointInput createUnregisterEndpointInput(NeutronPort port, ForwardingCtx fwCtx) {
-        UnregisterEndpointInputBuilder inputBuilder = new UnregisterEndpointInputBuilder();
-        L2 l2Ep = new L2Builder().setL2Context(fwCtx.getL2BridgeDomain().getId())
-            .setMacAddress(new MacAddress(port.getMacAddress()))
+    @Deprecated
+    private org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.UnregisterEndpointInput createUnregisterEndpointInput(
+            Port port, Neutron neutron) {
+        org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.UnregisterEndpointInputBuilder inputBuilder =
+                new org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.UnregisterEndpointInputBuilder();
+        L2 l2Ep = new L2Builder().setL2Context(new L2BridgeDomainId(port.getNetworkId().getValue()))
+            .setMacAddress(new MacAddress(port.getMacAddress().getValue()))
             .build();
         inputBuilder.setL2(ImmutableList.of(l2Ep));
-        // TODO Li msunal this has to be rewrite when OFOverlay renderer will support l3-endpoints.
-        // Endpoint probably will not have l3-addresses anymore, because L2 and L3 endpoints should
-        // be registered separately.
-        if (port.getFixedIPs() != null && !port.getFixedIPs().isEmpty()) {
-            inputBuilder.setL3(createL3s(port.getFixedIPs(), fwCtx.getL3Context().getId()));
+        // we've registered EP with only first IP so remove only EP with first IP
+        Optional<FixedIps> potentialFirstIp = PortUtils.resolveFirstFixedIps(port);
+        if (potentialFirstIp.isPresent()) {
+            FixedIps firstIp = potentialFirstIp.get();
+            L3Address l3Address = resolveL3AddressFromPort(port, firstIp, neutron);
+            L3 l3 = new L3Builder().setIpAddress(l3Address.getIpAddress())
+                .setL3Context(l3Address.getL3Context())
+                .build();
+            inputBuilder.setL3(ImmutableList.of(l3));
         }
         return inputBuilder.build();
     }
 
-    private List<L3> createL3s(List<Neutron_IPs> neutronIps, L3ContextId l3ContextId) {
-        List<L3> l3s = new ArrayList<>();
-        for (Neutron_IPs fixedIp : neutronIps) {
-            String ip = fixedIp.getIpAddress();
-            L3 l3 = new L3Builder().setIpAddress(Utils.createIpAddress(ip)).setL3Context(l3ContextId).build();
-            l3s.add(l3);
+    @Deprecated
+    private static L3Address resolveL3AddressFromPort(Port port, FixedIps portFixedIPs, Neutron neutron) {
+        Set<Port> routerIfacePorts = PortUtils.findRouterInterfacePorts(neutron.getPorts());
+        for (Port routerIfacePort : routerIfacePorts) {
+            Uuid routerIfacePortSubnet = routerIfacePort.getFixedIps().get(0).getSubnetId();
+            // if port is in the same subnet as router interface then we want to use L3Context of
+            // router
+            if (portFixedIPs.getSubnetId().equals(routerIfacePortSubnet)) {
+                L3ContextId epL3ContextId = new L3ContextId(routerIfacePort.getDeviceId());
+                LOG.trace("Router interface port was found in the same subnet as port have {}", port);
+                return new L3AddressBuilder().setL3Context(epL3ContextId)
+                    .setIpAddress(portFixedIPs.getIpAddress())
+                    .build();
+            }
         }
-        return l3s;
+        return new L3AddressBuilder().setL3Context(new L3ContextId(port.getNetworkId().getValue()))
+            .setIpAddress(portFixedIPs.getIpAddress())
+            .build();
     }
 
-    public static UniqueId getFloatingIpPortIdByDeviceId(String deviceId) {
-        return floatingIpPortByDeviceId.get(deviceId);
+    private static ContextId resolveL3ContextForPort(Port port, FixedIps portFixedIPs, Neutron neutron) {
+        Set<Port> routerIfacePorts = PortUtils.findRouterInterfacePorts(neutron.getPorts());
+        for (Port routerIfacePort : routerIfacePorts) {
+            Uuid routerIfacePortSubnet = routerIfacePort.getFixedIps().get(0).getSubnetId();
+            // if port is in the same subnet as router interface then we want to use L3Context of
+            // router
+            if (portFixedIPs.getSubnetId().equals(routerIfacePortSubnet)) {
+                LOG.trace("Router interface port was found in the same subnet as port have {}", port);
+                return new ContextId(routerIfacePort.getDeviceId());
+            }
+        }
+        return new ContextId(port.getNetworkId().getValue());
     }
-
 }