fix registerEndpoint in port delete for base Eps
[groupbasedpolicy.git] / neutron-mapper / src / main / java / org / opendaylight / groupbasedpolicy / neutron / mapper / mapping / NeutronPortAware.java
index e240de078eb5452bf67f5f1faed56e8033529f03..951d593855cb71a5ea6100032871f10f74492419 100644 (file)
@@ -10,8 +10,11 @@ package org.opendaylight.groupbasedpolicy.neutron.mapper.mapping;
 import static com.google.common.base.Preconditions.checkNotNull;
 
 import java.util.ArrayList;
+import java.util.Collections;
 import java.util.List;
 import java.util.Set;
+import java.util.concurrent.ExecutionException;
+import java.util.stream.Collectors;
 
 import javax.annotation.Nullable;
 
@@ -22,6 +25,7 @@ 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.MetadataService;
 import org.opendaylight.groupbasedpolicy.neutron.mapper.infrastructure.NetworkClient;
 import org.opendaylight.groupbasedpolicy.neutron.mapper.infrastructure.NetworkService;
 import org.opendaylight.groupbasedpolicy.neutron.mapper.util.MappingUtils;
@@ -29,6 +33,8 @@ 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.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.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;
@@ -37,6 +43,7 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpo
 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.AddressEndpoint;
 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;
@@ -61,9 +68,9 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.r
 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.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.l2_l3.rev170511.IpPrefixType;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.forwarding.l2_l3.rev170511.L3Context;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.forwarding.l2_l3.rev170511.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;
@@ -76,8 +83,11 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev
 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.port.attributes.FixedIpsBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.port.attributes.FixedIpsKey;
 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.ports.rev150712.ports.attributes.ports.PortBuilder;
 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;
@@ -86,6 +96,7 @@ import org.slf4j.LoggerFactory;
 
 import com.google.common.base.Optional;
 import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Lists;
 
 public class NeutronPortAware implements NeutronAware<Port> {
 
@@ -94,13 +105,17 @@ public class NeutronPortAware implements NeutronAware<Port> {
             InstanceIdentifier.builder(Neutron.class).child(Ports.class).child(Port.class).build();
     private final DataBroker dataProvider;
     private final EndpointRegistrator epRegistrator;
+    private final IpPrefix metadataIpPrefix;
 
-    public NeutronPortAware(DataBroker dataProvider, EndpointRegistrator epRegistrator) {
+    public NeutronPortAware(DataBroker dataProvider, EndpointRegistrator epRegistrator,
+            @Nullable IpPrefix metadataIpPrefix) {
         this.dataProvider = checkNotNull(dataProvider);
         this.epRegistrator = checkNotNull(epRegistrator);
+        this.metadataIpPrefix = checkNotNull(metadataIpPrefix);
     }
 
-    @Override public void onCreated(Port createdItem, Neutron neutron) {
+    @Override
+    public void onCreated(Port createdItem, Neutron neutron) {
         onCreated(createdItem, neutron, true);
     }
 
@@ -111,59 +126,51 @@ public class NeutronPortAware implements NeutronAware<Port> {
             // 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);
+                LOG.warn("Illegal state - router interface port does not contain fixed IPs {}", port);
                 return;
             }
             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);
+            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())) {
+            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);
+                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);
+                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);
             }
-
             // change L3Context for all EPs with same subnet as router port
-            changeL3ContextForEpsInSubnet(portIpWithSubnet.getSubnetId(), neutron);
+            changeL3ContextForEpsInSubnet(portIpWithSubnet.getSubnetId(), port.getNetworkId(),
+                    new Uuid(port.getDeviceId()), neutron, true);
             // 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());
+            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);
+                LOG.warn("Illegal state - router interface port is in subnet which does not exist. {}", port);
                 return;
             }
             Subnet routerPortSubnet = potentialRouterPortSubnet.get();
@@ -172,11 +179,12 @@ public class NeutronPortAware implements NeutronAware<Port> {
                 .setContextType(MappingUtils.L2_BRDIGE_DOMAIN)
                 .setParent(MappingUtils.createParent(routerL3Context, MappingUtils.L3_CONTEXT))
                 .build();
-            rwTx.merge(LogicalDatastoreType.CONFIGURATION, L2L3IidFactory.l2BridgeDomainIid(tenantId, l2BdId), l2Bd, true);
+            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);
+            NetworkDomain subnetDomain = NeutronSubnetAware.createSubnet(routerPortSubnet, neutron, null);
+            rwTx.merge(LogicalDatastoreType.CONFIGURATION,
+                    L2L3IidFactory.subnetIid(tenantId, subnetDomain.getNetworkDomainId()), subnetDomain);
 
             // does the same for tenant forwarding domains
             processTenantForwarding(routerPortSubnet, routerL3Context, portIpWithSubnet, tenantId, rwTx);
@@ -194,26 +202,24 @@ public class NeutronPortAware implements NeutronAware<Port> {
             NetworkDomainId networkContainment = new NetworkDomainId(ipWithSubnet.getSubnetId().getValue());
             List<EndpointGroupId> epgsFromSecGroups = resolveEpgIdsFromSecGroups(port.getSecurityGroups());
             epgsFromSecGroups.add(NetworkService.EPG_ID);
+            AddressEndpointRegBuilder l2BaseEp =
+                    createBasicMacAddrEpInputBuilder(port, networkContainment, Collections.emptyList());
+            AddressEndpointRegBuilder l3BaseEp =
+                    createBasicL3AddrEpInputBuilder(port, networkContainment, epgsFromSecGroups, neutron);
 
-            // 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);
-
+            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);
+            registerBaseEndpointAndStoreMapping(ImmutableList.of(l3BaseEp.build(), l2BaseEp.build()), port, rwTx,
+                    addBaseEpMapping);
+            registerMetadataServiceForDhcpPort(port, neutron, l2BaseEp, rwTx, true);
             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;
+            org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.RegisterEndpointInputBuilder epInBuilder =
+                    null;
             AddressEndpointRegBuilder l2BaseEp;
             AddressEndpointRegBuilder l3BaseEp = null;
             Optional<FixedIps> firstFixedIps = PortUtils.resolveFirstFixedIps(port);
@@ -224,8 +230,7 @@ public class NeutronPortAware implements NeutronAware<Port> {
                 FixedIps ipWithSubnet = firstFixedIps.get();
                 NetworkDomainId containment = new NetworkDomainId(ipWithSubnet.getSubnetId().getValue());
                 epInBuilder = createEndpointRegFromPort(port, ipWithSubnet, containment, epgsFromSecGroups, neutron);
-                l2BaseEp = createBasicMacAddrEpInputBuilder(port,
-                        containment, epgsFromSecGroups);
+                l2BaseEp = createBasicMacAddrEpInputBuilder(port, containment, epgsFromSecGroups);
                 l3BaseEp = createBasicL3AddrEpInputBuilder(port, containment, epgsFromSecGroups, neutron);
                 setParentChildRelationshipForEndpoints(l3BaseEp, l2BaseEp);
             } else {
@@ -253,10 +258,43 @@ public class NeutronPortAware implements NeutronAware<Port> {
         }
     }
 
+    private Port cloneMetadataPortFromDhcpPort(Port port, IpPrefix metadataPrefix) {
+        IpAddress metadataIp = MappingUtils.ipPrefixToIpAddress(metadataPrefix);
+        List<FixedIps> metadataIps = port.getFixedIps().stream().map(fi -> {
+            FixedIpsKey key = new FixedIpsKey(metadataIp, fi.getKey().getSubnetId());
+            return new FixedIpsBuilder(fi).setKey(key).setIpAddress(metadataIp).build();
+        }).collect(Collectors.toList());
+        return new PortBuilder(port).setFixedIps(metadataIps).build();
+    }
+
+    private void registerMetadataServiceForDhcpPort(Port port, Neutron neutron, AddressEndpointRegBuilder childEpToAdd,
+            ReadWriteTransaction rwTx, boolean registerMapping) {
+        Optional<NetworkDomainId> resolveNetworkContainment = PortUtils.resolveNetworkContainment(port);
+        if (!resolveNetworkContainment.isPresent()) {
+            LOG.warn("DHCP port does not have an IP address. {}", port);
+            return;
+        }
+        AddressEndpointRegBuilder metadataEp =
+                createBasicL3AddrEpInputBuilder(cloneMetadataPortFromDhcpPort(port, metadataIpPrefix),
+                        resolveNetworkContainment.get(), Lists.newArrayList(MetadataService.EPG_ID), neutron);
+        AddressEndpointKey aek = new AddressEndpointKey(metadataEp.getAddress(), metadataEp.getAddressType(),
+                metadataEp.getContextId(), metadataEp.getContextType());
+        Optional<AddressEndpoint> optMetadataEp =
+                DataStoreHelper.readFromDs(LogicalDatastoreType.OPERATIONAL, IidFactory.addressEndpointIid(aek), rwTx);
+        if (!optMetadataEp.isPresent()) {
+            setParentChildRelationshipForEndpoints(metadataEp, childEpToAdd);
+        } else {
+            List<ChildEndpoint> childs = optMetadataEp.get().getChildEndpoint();
+            childs.add(createChildEndpoint(childEpToAdd));
+            metadataEp.setChildEndpoint(childs);
+        }
+        registerBaseEndpointAndStoreMapping(ImmutableList.of(metadataEp.build()), port, rwTx, registerMapping);
+    }
+
     private void setParentChildRelationshipForEndpoints(AddressEndpointRegBuilder parentEp,
             AddressEndpointRegBuilder childEp) {
-        childEp.setParentEndpointChoice(new ParentEndpointCaseBuilder().setParentEndpoint(
-                ImmutableList.<ParentEndpoint>of(createParentEndpoint(parentEp))).build());
+        childEp.setParentEndpointChoice(new ParentEndpointCaseBuilder()
+            .setParentEndpoint(ImmutableList.<ParentEndpoint>of(createParentEndpoint(parentEp))).build());
         parentEp.setChildEndpoint(ImmutableList.<ChildEndpoint>of(createChildEndpoint(childEp)));
     }
 
@@ -264,11 +302,12 @@ public class NeutronPortAware implements NeutronAware<Port> {
     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();
+        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());
+        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);
     }
 
@@ -279,9 +318,10 @@ public class NeutronPortAware implements NeutronAware<Port> {
      */
     @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);
+            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));
@@ -290,38 +330,79 @@ public class NeutronPortAware implements NeutronAware<Port> {
         return epInBuilder;
     }
 
-    private void changeL3ContextForEpsInSubnet(Uuid subnetUuid, Neutron neutron) {
+    private void changeL3ContextForEpsInSubnet(Uuid subnetUuid, Uuid networkId, Uuid routerId, Neutron neutron,
+            boolean routerInterfAdded) {
+        if (neutron == null) {
+            LOG.debug("No new data are written, there is no L3 context in subnet {} to update", subnetUuid);
+            return;
+        }
+        java.util.Optional<Subnet> optSubnet = neutron.getSubnets()
+            .getSubnet()
+            .stream()
+            .filter(subnet -> subnet.getNetworkId() != null
+                    && subnet.getUuid().getValue().equals(subnetUuid.getValue()))
+            .findAny();
+        if (!optSubnet.isPresent()) {
+            LOG.error("Failed to update metadata endpoint in subnet {}. Could not resolve Network ID", subnetUuid);
+        } else {
+            AddressEndpointUnregBuilder metadataEpUnreg =
+                    new AddressEndpointUnregBuilder().setAddress(String.valueOf(metadataIpPrefix.getValue()))
+                        .setAddressType(IpPrefixType.class)
+                        .setContextType(MappingUtils.L3_CONTEXT);
+            if (routerInterfAdded) {
+                metadataEpUnreg.setContextId(new ContextId(networkId.getValue()));
+            } else {
+                metadataEpUnreg.setContextId(new ContextId(routerId.getValue()));
+            }
+            epRegistrator.unregisterEndpoint(metadataEpUnreg.build());
+        }
         Set<Port> portsInSameSubnet = PortUtils.findPortsBySubnet(subnetUuid, neutron.getPorts());
         for (Port portInSameSubnet : portsInSameSubnet) {
             if (PortUtils.isNormalPort(portInSameSubnet) || PortUtils.isDhcpPort(portInSameSubnet)
-                || PortUtils.isQrouterOrVppRouterPort(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)) {
+                    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 l2BaseEp =
+                            createBasicMacAddrEpInputBuilder(portInSameSubnet, networkContainment, endpointGroupIds);
                     AddressEndpointRegBuilder l3BaseEp = createBasicL3AddrEpInputBuilder(portInSameSubnet,
                             networkContainment, endpointGroupIds, neutron);
+
+                    setParentChildRelationshipForEndpoints(l3BaseEp, l2BaseEp);
+                    AddressEndpointUnregBuilder addrEpUnreg =
+                            new AddressEndpointUnregBuilder().setAddress(l3BaseEp.getAddress())
+                                .setAddressType(l3BaseEp.getAddressType())
+                                .setContextType(l3BaseEp.getContextType());
+                    if (routerInterfAdded) {
+                        addrEpUnreg.setContextId(new ContextId(networkId.getValue()));
+                    } else {
+                        addrEpUnreg.setContextId(new ContextId(routerId.getValue()));
+                    }
+                    epRegistrator.unregisterEndpoint(addrEpUnreg.build());
+                    if (routerInterfAdded) {
+                        l3BaseEp.setContextId(new ContextId(routerId.getValue()));
+                    } else {
+                        l3BaseEp.setContextId(new ContextId(networkId.getValue()));
+                    }
                     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);
-
+                    if (PortUtils.isDhcpPort(portInSameSubnet)) {
+                        ReadWriteTransaction rwTx = dataProvider.newReadWriteTransaction();
+                        registerMetadataServiceForDhcpPort(portInSameSubnet, neutron, l2BaseEp, rwTx, false);
+                        DataStoreHelper.submitToDs(rwTx);
+                    }
                     modifyL3ContextForEndpoints(portInSameSubnet, ipWithSubnet, l3BaseEp.getContextId());
                 }
             }
@@ -346,7 +427,8 @@ public class NeutronPortAware implements NeutronAware<Port> {
 
     @Deprecated
     private void modifyL3ContextForEndpoints(Port port, FixedIps resolvedPortFixedIp, ContextId newContextId) {
-        org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.RegisterEndpointInputBuilder epInBuilder = createBasicEndpointInputBuilder(port);
+        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())
@@ -359,14 +441,14 @@ public class NeutronPortAware implements NeutronAware<Port> {
         // 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();
+        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);
     }
 
-    private AddressEndpointRegBuilder createBasicMacAddrEpInputBuilder(Port port,
-            NetworkDomainId networkContainment, @Nullable List<EndpointGroupId> endpointGroupsToAdd) {
+    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)
@@ -377,10 +459,11 @@ public class NeutronPortAware implements NeutronAware<Port> {
         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());
+            addrEpbuilder.setNetworkContainment(new NetworkContainmentBuilder()
+                .setContainment(new NetworkDomainContainmentBuilder().setNetworkDomainId(networkContainment)
+                    .setNetworkDomainType(MappingUtils.SUBNET)
+                    .build())
+                .build());
         }
         return addrEpbuilder;
     }
@@ -389,8 +472,8 @@ public class NeutronPortAware implements NeutronAware<Port> {
             @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.");
+            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);
 
@@ -404,10 +487,11 @@ public class NeutronPortAware implements NeutronAware<Port> {
         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());
+            addrEpbuilder.setNetworkContainment(new NetworkContainmentBuilder()
+                .setContainment(new NetworkDomainContainmentBuilder().setNetworkDomainId(networkContainment)
+                    .setNetworkDomainType(MappingUtils.SUBNET)
+                    .build())
+                .build());
         }
         return addrEpbuilder;
     }
@@ -429,8 +513,8 @@ public class NeutronPortAware implements NeutronAware<Port> {
     @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()))
+        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());
@@ -453,16 +537,17 @@ public class NeutronPortAware implements NeutronAware<Port> {
             Port port, ReadWriteTransaction rwTx) {
         boolean isRegisteredEndpoint = epRegistrator.registerEndpoint(regEpInput);
         if (!isRegisteredEndpoint) {
-            LOG.error("Failed to register an endpoint: {}", regEpInput);
+            LOG.error("Failed to register 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);
+        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);
+        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,
@@ -476,10 +561,10 @@ public class NeutronPortAware implements NeutronAware<Port> {
         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);
+            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.endpointByPortIid(portId), rwTx);
             DataStoreHelper.removeIfExists(LogicalDatastoreType.OPERATIONAL,
@@ -489,12 +574,12 @@ public class NeutronPortAware implements NeutronAware<Port> {
 
     private void registerBaseEndpointAndStoreMapping(List<AddressEndpointReg> addrEpRegs, Port port,
             WriteTransaction wTx, boolean addBaseEpMappings) {
-        RegisterEndpointInput regBaseEpInput = new RegisterEndpointInputBuilder().setAddressEndpointReg(addrEpRegs)
-            .build();
+        RegisterEndpointInput regBaseEpInput =
+                new RegisterEndpointInputBuilder().setAddressEndpointReg(addrEpRegs).build();
 
         boolean isRegisteredBaseEndpoint = epRegistrator.registerEndpoint(regBaseEpInput);
         if (!isRegisteredBaseEndpoint) {
-            LOG.error("Failed to register an address endpoint: {}", addrEpRegs);
+            LOG.error("Failed to register address endpoint: {}", addrEpRegs);
             return;
         }
         for (AddressEndpointReg addrEpReg : addrEpRegs) {
@@ -515,8 +600,8 @@ public class NeutronPortAware implements NeutronAware<Port> {
                 baseEndpointByPort, true);
         PortByBaseEndpoint portByBaseEndpoint = MappingFactory.createPortByBaseEndpoint(portId, addrEpKey);
         wTx.put(LogicalDatastoreType.OPERATIONAL,
-                NeutronGbpIidFactory.portByBaseEndpointIid(new PortByBaseEndpointKey(
-                        portByBaseEndpoint.getKey())), portByBaseEndpoint, true);
+                NeutronGbpIidFactory.portByBaseEndpointIid(new PortByBaseEndpointKey(portByBaseEndpoint.getKey())),
+                portByBaseEndpoint, true);
     }
 
     private void unregisterEndpointAndRemoveMapping(UnregisterEndpointInput baseEpUnreg, Port port,
@@ -534,7 +619,8 @@ public class NeutronPortAware implements NeutronAware<Port> {
         }
     }
 
-    private void removeBaseEndpointMappings(PortByBaseEndpointKey portByBaseEndpointKey, UniqueId portId, ReadWriteTransaction rwTx) {
+    private void removeBaseEndpointMappings(PortByBaseEndpointKey portByBaseEndpointKey, UniqueId portId,
+            ReadWriteTransaction rwTx) {
         DataStoreHelper.removeIfExists(LogicalDatastoreType.OPERATIONAL,
                 NeutronGbpIidFactory.baseEndpointByPortIid(portId), rwTx);
         DataStoreHelper.removeIfExists(LogicalDatastoreType.OPERATIONAL,
@@ -544,33 +630,34 @@ public class NeutronPortAware implements NeutronAware<Port> {
     @Override
     public void onUpdated(Port oldPort, Port newPort, Neutron oldNeutron, Neutron newNeutron) {
         LOG.trace("updated port - OLD: {}\nNEW: {}", oldPort, newPort);
-        onDeleted(oldPort, oldNeutron, false);
+        onDeleted(oldPort, oldNeutron, newNeutron, false);
         onCreated(newPort, newNeutron, false);
     }
 
-    @Override public void onDeleted(Port deletedItem, Neutron oldNeutron, Neutron newNeutron) {
-        onDeleted(deletedItem, oldNeutron, true);
+    @Override
+    public void onDeleted(Port deletedItem, Neutron oldNeutron, Neutron newNeutron) {
+        onDeleted(deletedItem, oldNeutron, newNeutron, true);
     }
 
-    public void onDeleted(Port port, Neutron oldNeutron, boolean removeBaseEpMapping) {
+    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);
+                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(), oldNeutron);
+            // change L3Context for all new EPs with same subnet as router port
+            changeL3ContextForEpsInSubnet(portIpWithSubnet.getSubnetId(), port.getNetworkId(),
+                    new Uuid(port.getDeviceId()), newNeutron, false);
             // 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());
+            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;
@@ -585,27 +672,43 @@ public class NeutronPortAware implements NeutronAware<Port> {
                 .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);
-            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);
-            if (removeBaseEpMapping) {
-                removeBaseEndpointMappings(portByBaseEndpointKey, portId, rwTx);
-            }
+            NetworkDomain subnet = NeutronSubnetAware.createSubnet(routerPortSubnet, newNeutron, 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);
+            unregisterEndpointAndRemoveMapping(createUnregisterBaseEndpointInput(port, oldNeutron), port, rwTx,
+                    removeBaseEpMapping);
             DataStoreHelper.submitToDs(rwTx);
+            if (!oldNeutron.getPorts()
+                .getPort()
+                .stream()
+                .filter(PortUtils::isDhcpPort)
+                .anyMatch(p -> !p.getUuid().equals(port.getUuid()))) {
+                Port metadataPort = cloneMetadataPortFromDhcpPort(port, metadataIpPrefix);
+                if (PortUtils.resolveFirstFixedIps(metadataPort).isPresent()) {
+                    ContextId metadataCtx = resolveL3ContextForPort(metadataPort,
+                            PortUtils.resolveFirstFixedIps(metadataPort).get(), oldNeutron);
+                    AddressEndpointUnregBuilder metadataEpUnreg =
+                            new AddressEndpointUnregBuilder().setAddress(String.valueOf(metadataIpPrefix.getValue()))
+                                .setAddressType(IpPrefixType.class)
+                                .setContextType(MappingUtils.L3_CONTEXT)
+                                .setContextId(metadataCtx);
+                    epRegistrator.unregisterEndpoint(metadataEpUnreg.build());
+                }
+            }
         } 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);
+            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
@@ -619,13 +722,16 @@ public class NeutronPortAware implements NeutronAware<Port> {
     }
 
     @Deprecated
-    private void modifyForwardingOnDelete(Subnet routerPortSubnet, L3ContextId l3contextId, TenantId tenantId, ReadWriteTransaction rwTx) {
+    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);
+        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 org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.UnregisterEndpointInput createUnregisterBaseEndpointInput(
@@ -642,7 +748,8 @@ public class NeutronPortAware implements NeutronAware<Port> {
         if (potentialFirstIp.isPresent()) {
             ContextId l3ContextId = resolveL3ContextForPort(port, potentialFirstIp.get(), neutron);
             AddressEndpointUnregBuilder addrL3EpUnregBuilder = new AddressEndpointUnregBuilder();
-            addrL3EpUnregBuilder.setAddress(MappingUtils.ipAddressToStringIpPrefix(potentialFirstIp.get().getIpAddress()))
+            addrL3EpUnregBuilder
+                .setAddress(MappingUtils.ipAddressToStringIpPrefix(potentialFirstIp.get().getIpAddress()))
                 .setAddressType(IpPrefixType.class)
                 .setContextId(l3ContextId)
                 .setContextType(L3Context.class);