Fix fileEncoding violations for checkstyle
[groupbasedpolicy.git] / neutron-vpp-mapper / src / main / java / org / opendaylight / groupbasedpolicy / neutron / vpp / mapper / processors / PortHandler.java
index adf92cc3f43d5be3199eb7c202a29ef6e3fd2eaf..12f08cfb9a969e8adc59375961c37bb4a5275935 100644 (file)
-/*\r
- * Copyright (c) 2016 Cisco Systems, Inc. and others. All rights reserved.\r
- *\r
- * This program and the accompanying materials are made available under the\r
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,\r
- * and is available at http://www.eclipse.org/legal/epl-v10.html\r
- */\r
-\r
-package org.opendaylight.groupbasedpolicy.neutron.vpp.mapper.processors;\r
-\r
-import java.util.Collections;\r
-import java.util.List;\r
-\r
-import javax.annotation.Nonnull;\r
-import javax.annotation.Nullable;\r
-\r
-import org.opendaylight.controller.md.sal.binding.api.DataBroker;\r
-import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;\r
-import org.opendaylight.controller.md.sal.common.api.data.AsyncTransaction;\r
-import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;\r
-import org.opendaylight.controller.md.sal.common.api.data.TransactionChain;\r
-import org.opendaylight.controller.md.sal.common.api.data.TransactionChainListener;\r
-import org.opendaylight.groupbasedpolicy.util.DataStoreHelper;\r
-import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress;\r
-import org.opendaylight.groupbasedpolicy.util.SyncedChain;\r
-import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpPrefix;\r
-import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv4Prefix;\r
-import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.PhysAddress;\r
-import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;\r
-import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.UniqueId;\r
-import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.neutron.gbp.mapper.rev150513.Mappings;\r
-import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.neutron.gbp.mapper.rev150513.mappings.GbpByNeutronMappings;\r
-import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.neutron.gbp.mapper.rev150513.mappings.gbp.by.neutron.mappings.BaseEndpointsByPorts;\r
-import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.neutron.gbp.mapper.rev150513.mappings.gbp.by.neutron.mappings.base.endpoints.by.ports.BaseEndpointByPort;\r
-import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.neutron.gbp.mapper.rev150513.mappings.gbp.by.neutron.mappings.base.endpoints.by.ports.BaseEndpointByPortKey;\r
-import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.vpp_renderer.rev160425.Config;\r
-import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.vpp_renderer.rev160425.ExcludeFromPolicy;\r
-import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.vpp_renderer.rev160425.ExcludeFromPolicyBuilder;\r
-import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.vpp_renderer.rev160425._interface.attributes._interface.type.choice.LoopbackCase;\r
-import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.vpp_renderer.rev160425._interface.attributes._interface.type.choice.LoopbackCaseBuilder;\r
-import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.vpp_renderer.rev160425._interface.attributes._interface.type.choice.TapCase;\r
-import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.vpp_renderer.rev160425._interface.attributes._interface.type.choice.TapCaseBuilder;\r
-import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.vpp_renderer.rev160425._interface.attributes._interface.type.choice.VhostUserCaseBuilder;\r
-import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.vpp_renderer.rev160425.config.VppEndpoint;\r
-import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.vpp_renderer.rev160425.config.VppEndpointBuilder;\r
-import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.vpp_renderer.rev160425.config.VppEndpointKey;\r
-import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.binding.rev150712.PortBindingExtension;\r
-import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.binding.rev150712.binding.attributes.VifDetails;\r
-import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.l3.rev150712.routers.attributes.Routers;\r
-import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.l3.rev150712.routers.attributes.routers.Router;\r
-import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.l3.rev150712.routers.attributes.routers.RouterKey;\r
-import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.port.attributes.FixedIps;\r
-import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.ports.attributes.Ports;\r
-import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.ports.attributes.ports.Port;\r
-import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.ports.attributes.ports.PortKey;\r
-import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.portsecurity.rev150712.PortSecurityExtension;\r
-import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.rev150712.Neutron;\r
-import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.subnets.rev150712.subnets.attributes.Subnets;\r
-import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.subnets.rev150712.subnets.attributes.subnets.Subnet;\r
-import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.subnets.rev150712.subnets.attributes.subnets.SubnetKey;\r
-import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;\r
-import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;\r
-import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.InstanceIdentifierBuilder;\r
-import org.slf4j.Logger;\r
-import org.slf4j.LoggerFactory;\r
-\r
-import com.google.common.annotations.VisibleForTesting;\r
-import com.google.common.base.Optional;\r
-import com.google.common.base.Preconditions;\r
-import com.google.common.base.Strings;\r
-\r
-public class PortHandler implements TransactionChainListener {\r
-\r
-    private static final Logger LOG = LoggerFactory.getLogger(PortHandler.class);\r
-\r
-    private static final String COMPUTE_OWNER = "compute";\r
-    private static final String DHCP_OWNER = "dhcp";\r
-    static final String ROUTER_OWNER = "network:router_interface";\r
-    private static final String[] SUPPORTED_DEVICE_OWNERS = {COMPUTE_OWNER, DHCP_OWNER, ROUTER_OWNER};\r
-    private static final String VHOST_USER = "vhostuser";\r
-    private static final String UNBOUND = "unbound";\r
-    private static final String VPP_INTERFACE_NAME_PREFIX = "neutron_port_";\r
-    private static final String TAP_PORT_NAME_PREFIX = "tap";\r
-    private static final String RT_PORT_NAME_PREFIX = "qr-";\r
-    private static final String VHOST_SOCKET_KEY = "vhostuser_socket";\r
-    static final String DEFAULT_NODE = "default";\r
-\r
-    private final NodeId routingNode;\r
-    private SyncedChain syncedChain;\r
-    private DataBroker dataBroker;\r
-\r
-    PortHandler(DataBroker dataBroker, NodeId routingNodeId) {\r
-        this.dataBroker = dataBroker;\r
-        this.routingNode = routingNodeId;\r
-        this.syncedChain = new SyncedChain(Preconditions.checkNotNull(dataBroker.createTransactionChain(this)));\r
-    }\r
-\r
-    void processCreated(Port port) {\r
-        Optional<BaseEndpointByPort> optBaseEpByPort =\r
-                syncedChain.readFromDs(LogicalDatastoreType.OPERATIONAL, createBaseEpByPortIid(port.getUuid()));\r
-        if (!optBaseEpByPort.isPresent()) {\r
-            return;\r
-        }\r
-        processCreatedData(port, optBaseEpByPort.get());\r
-    }\r
-\r
-    void processCreated(BaseEndpointByPort bebp) {\r
-        Optional<Port> optPort =\r
-                syncedChain.readFromDs(LogicalDatastoreType.CONFIGURATION, createPortIid(bebp.getPortId()));\r
-        if (!optPort.isPresent()) {\r
-            return;\r
-        }\r
-        processCreatedData(optPort.get(), bebp);\r
-    }\r
-\r
-    @VisibleForTesting\r
-    void processCreatedData(Port port, BaseEndpointByPort bebp) {\r
-        if (isValidVhostUser(port)\r
-                // this is a hack for vpp router port\r
-                // Openstack does not send binding details yet\r
-                || isValidVppRouterPort(port)) {\r
-            VppEndpoint vppEp = buildVppEndpoint(port, bebp);\r
-            if (vppEp == null) {\r
-                LOG.warn("Cannot create vpp-endpoint from neutron port {}", port);\r
-                return;\r
-            }\r
-            writeVppEndpoint(createVppEndpointIid(vppEp.getKey()), vppEp);\r
-            LOG.debug("Created vpp-endpoint {}", vppEp);\r
-        }\r
-    }\r
-\r
-    private boolean isValidVhostUser(Port port) {\r
-        PortBindingExtension portBindingExt = port.getAugmentation(PortBindingExtension.class);\r
-        if (portBindingExt != null) {\r
-            String vifType = portBindingExt.getVifType();\r
-            String deviceOwner = port.getDeviceOwner();\r
-            if (vifType != null && deviceOwner != null) {\r
-                if (vifType.contains(VHOST_USER)) {\r
-                    for (String supportedDeviceOwner : SUPPORTED_DEVICE_OWNERS) {\r
-                        if (deviceOwner.contains(supportedDeviceOwner)) {\r
-                            return true;\r
-                        }\r
-                    }\r
-                }\r
-            }\r
-        }\r
-        return false;\r
-    }\r
-\r
-    void processUpdated(Port original, Port delta) {\r
-        if (!isUpdateNeeded(original, delta)) {\r
-            LOG.trace("Port update skipped, port didn`t change. before {}, after: {}", original, delta);\r
-            return;\r
-        }\r
-\r
-        LOG.trace("Updating port before: {}, after: {}", original, delta);\r
-        if (isValidVhostUser(original)) {\r
-            Optional<BaseEndpointByPort> optBebp =\r
-                    syncedChain.readFromDs(LogicalDatastoreType.OPERATIONAL, createBaseEpByPortIid(original.getUuid()));\r
-            if (!optBebp.isPresent()) {\r
-                return;\r
-            }\r
-            LOG.trace("Updating port - deleting old port {}", optBebp.get().getPortId());\r
-            processDeleted(optBebp.get());\r
-        }\r
-        LOG.trace("Updating port - creating new port {}", delta.getUuid());\r
-        processCreated(delta);\r
-    }\r
-\r
-    private boolean isUpdateNeeded(final Port oldPort, final Port newPort) {\r
-        // TODO fix this to better support update of ports for VPP\r
-        final PortBindingExtension oldPortAugmentation = oldPort.getAugmentation(PortBindingExtension.class);\r
-        final PortBindingExtension newPortAugmentation = newPort.getAugmentation(PortBindingExtension.class);\r
-\r
-        if (newPortAugmentation == null) {\r
-            LOG.trace("Port {} is no longer a vhost type port, updating port...");\r
-            return true;\r
-        }\r
-\r
-        final String oldDeviceOwner = oldPort.getDeviceOwner();\r
-        final String oldVifType = oldPortAugmentation.getVifType();\r
-        final String newDeviceOwner = newPort.getDeviceOwner();\r
-        final String newVifType = newPortAugmentation.getVifType();\r
-\r
-        // TODO potential bug here\r
-        // Temporary change for Openstack Mitaka: If old neutron-binding:vif-type is vhost, new one\r
-        // is unbound and\r
-        // device owner is ROUTER_OWNER, skip update. Openstack (or ml2) sometimes sends router\r
-        // update messages in\r
-        // incorrect order which causes unwanted port removal\r
-        if (oldVifType.equals(VHOST_USER) && newVifType.equals(UNBOUND) && oldDeviceOwner != null\r
-                && ROUTER_OWNER.equals(oldDeviceOwner) && ROUTER_OWNER.equals(newDeviceOwner)) {\r
-            LOG.warn(\r
-                    "Port vif-type was updated from vhost to unbound. This update is currently disabled and will be skipped");\r
-            return false;\r
-        }\r
-\r
-        if (newVifType != null && !newVifType.equals(oldVifType)) {\r
-            LOG.trace("Vif type changed, old: {} new {}", oldVifType, newVifType);\r
-            return true;\r
-        }\r
-\r
-        final List<VifDetails> vifDetails = oldPortAugmentation.getVifDetails();\r
-\r
-        if (!oldPortAugmentation.getHostId().equals(newPortAugmentation.getHostId())\r
-                || nullToEmpty(vifDetails).size() != nullToEmpty(newPortAugmentation.getVifDetails()).size()) {\r
-            return true;\r
-        }\r
-\r
-        for (VifDetails vifDetail : nullToEmpty(vifDetails)) {\r
-            // check if vhostuser_socket, vhostuser_mode and port_filter are changed\r
-            if (!newPortAugmentation.getVifDetails().contains(vifDetail))\r
-                return true;\r
-        }\r
-        return false;\r
-    }\r
-\r
-    void processDeleted(BaseEndpointByPort bebp) {\r
-        LOG.trace("Deleting vpp-endpoint by BaseEndpointByPort {}", bebp);\r
-        VppEndpointKey vppEpKey = new VppEndpointKey(bebp.getAddress(), bebp.getAddressType(), bebp.getContextId(),\r
-                bebp.getContextType());\r
-        InstanceIdentifier<VppEndpoint> vppEpIid = createVppEndpointIid(vppEpKey);\r
-        Optional<VppEndpoint> readVppEp = syncedChain.readFromDs(LogicalDatastoreType.CONFIGURATION, vppEpIid);\r
-        if (readVppEp.isPresent()) {\r
-            writeVppEndpoint(vppEpIid, null);\r
-            LOG.debug("Deleted vpp-endpoint {}", vppEpKey);\r
-        }\r
-    }\r
-\r
-    private synchronized void writeVppEndpoint(InstanceIdentifier<VppEndpoint> vppEpIid, VppEndpoint vppEp) {\r
-        WriteTransaction wTx = syncedChain.newWriteOnlyTransaction();\r
-        if (vppEp != null) {\r
-            wTx.put(LogicalDatastoreType.CONFIGURATION, vppEpIid, vppEp, true);\r
-        } else {\r
-            wTx.delete(LogicalDatastoreType.CONFIGURATION, vppEpIid);\r
-        }\r
-        syncedChain.submitNow(wTx);\r
-    }\r
-\r
-    @VisibleForTesting\r
-    VppEndpoint buildVppEndpoint(Port port, BaseEndpointByPort bebp) {\r
-        PortBindingExtension portBinding = port.getAugmentation(PortBindingExtension.class);\r
-        ExcludeFromPolicy excludeFromPolicy = new ExcludeFromPolicyBuilder().setExcludeFromPolicy(true).build();\r
-        VppEndpointBuilder vppEpBuilder = new VppEndpointBuilder().setDescription("neutron port")\r
-            .setContextId(bebp.getContextId())\r
-            .setContextType(bebp.getContextType())\r
-            .setAddress(bebp.getAddress())\r
-            .setAddressType(bebp.getAddressType())\r
-            .setVppInterfaceName(VPP_INTERFACE_NAME_PREFIX + bebp.getPortId().getValue())\r
-            .setVppNodeId(new NodeId(portBinding.getHostId()));\r
-\r
-        if (port.getDeviceOwner().contains(COMPUTE_OWNER)) {\r
-            vppEpBuilder.setInterfaceTypeChoice(\r
-                    new VhostUserCaseBuilder().setSocket(getSocketFromPortBinding(portBinding)).build());\r
-            Optional<PortSecurityExtension> portSecurity =\r
-                    Optional.fromNullable(port.getAugmentation(PortSecurityExtension.class));\r
-            if (portSecurity.isPresent() && !portSecurity.get().isPortSecurityEnabled()) {\r
-                vppEpBuilder.addAugmentation(ExcludeFromPolicy.class, excludeFromPolicy);\r
-            }\r
-\r
-        } else if (port.getDeviceOwner().contains(DHCP_OWNER) && port.getMacAddress() != null) {\r
-            IpAddress dhcpServerIpAddress = port.getFixedIps().stream().findFirst().isPresent() ?\r
-                port.getFixedIps().stream().findFirst().get().getIpAddress() : null;\r
-            TapCase tapCase = new TapCaseBuilder().setPhysicalAddress(new PhysAddress(port.getMacAddress().getValue()))\r
-                .setName(createPortName(port.getUuid()))\r
-                .setDhcpServerAddress(dhcpServerIpAddress)\r
-                .build();\r
-            vppEpBuilder.setInterfaceTypeChoice(tapCase);\r
-\r
-        } else if (isValidQRouterPort(port)) {\r
-            TapCase tapCase = new TapCaseBuilder().setPhysicalAddress(new PhysAddress(port.getMacAddress().getValue()))\r
-                .setName(createQRouterPortName(port.getUuid()))\r
-                .build();\r
-            vppEpBuilder.setInterfaceTypeChoice(tapCase);\r
-            vppEpBuilder.addAugmentation(ExcludeFromPolicy.class, excludeFromPolicy);\r
-\r
-        } else if (isValidVppRouterPort(port)) {\r
-            if (!DEFAULT_NODE.equals(routingNode.getValue())) {\r
-                LOG.warn(\r
-                        "Host-id changed by ODL for port {}. This is a supplementary workaround for choosing a routing node.",\r
-                        port);\r
-                vppEpBuilder.setVppNodeId(routingNode);\r
-            } else if (port.getDeviceId() != null) {\r
-                LOG.debug("Resolving host-id for unbound router port {}", port.getUuid());\r
-                Optional<Ports> optPorts = syncedChain.readFromDs(LogicalDatastoreType.CONFIGURATION,\r
-                        InstanceIdentifier.builder(Neutron.class).child(Ports.class).build());\r
-                if (optPorts.isPresent() && optPorts.get().getPort() != null) {\r
-                    java.util.Optional<Port> optPortOnTheSameNode = optPorts.get()\r
-                        .getPort()\r
-                        .stream()\r
-                        .filter(p -> !p.getUuid().equals(port.getUuid()))\r
-                        .filter(p -> p.getAugmentation(PortBindingExtension.class) != null)\r
-                        .filter(p -> p.getDeviceOwner().contains(DHCP_OWNER))\r
-                        .findFirst();\r
-                    if (optPortOnTheSameNode.isPresent()) {\r
-                        PortBindingExtension binding =\r
-                                optPortOnTheSameNode.get().getAugmentation(PortBindingExtension.class);\r
-                        if (binding != null && binding.getHostId() != null) {\r
-                            vppEpBuilder.setVppNodeId(new NodeId(binding.getHostId()));\r
-                        } else {\r
-                            LOG.warn("Cannot resolve location of router-port {}", port.getUuid());\r
-                            return null;\r
-                        }\r
-                    }\r
-                }\r
-            }\r
-            vppEpBuilder.addAugmentation(ExcludeFromPolicy.class, excludeFromPolicy);\r
-            vppEpBuilder.setInterfaceTypeChoice(getLoopbackCase(port));\r
-        }\r
-        return vppEpBuilder.build();\r
-    }\r
-\r
-    private String getSocketFromPortBinding(@Nonnull PortBindingExtension portBindingExtension) {\r
-        List<VifDetails> vifDetails = nullToEmpty(portBindingExtension.getVifDetails());\r
-\r
-        for (VifDetails detail : vifDetails) {\r
-            if (VHOST_SOCKET_KEY.equalsIgnoreCase(detail.getDetailsKey())) {\r
-                return detail.getValue();\r
-            }\r
-        }\r
-        return null;\r
-    }\r
-\r
-    private LoopbackCase getLoopbackCase(Port port) {\r
-        LoopbackCaseBuilder loopbackCase =\r
-                new LoopbackCaseBuilder().setPhysAddress(new PhysAddress(port.getMacAddress().getValue()));\r
-        Optional<FixedIps> fixedIpsOptional = resolveFirstFixedIps(port);\r
-        if (fixedIpsOptional.isPresent() && fixedIpsOptional.get().getIpAddress() != null) {\r
-            loopbackCase.setIpAddress(fixedIpsOptional.get().getIpAddress());\r
-            Optional<Subnet> subnetOptional = syncedChain.readFromDs(LogicalDatastoreType.CONFIGURATION,\r
-                    InstanceIdentifier.builder(Neutron.class)\r
-                        .child(Subnets.class)\r
-                        .child(Subnet.class, new SubnetKey(fixedIpsOptional.get().getSubnetId()))\r
-                        .build());\r
-            if (subnetOptional.isPresent()) {\r
-                Ipv4Prefix ipv4Prefix = subnetOptional.get().getCidr().getIpv4Prefix();\r
-                loopbackCase.setIpPrefix(new IpPrefix(ipv4Prefix));\r
-            } else {\r
-                LOG.warn("IpPrefix for loopback port: {} was not set.", port);\r
-            }\r
-            if (loopbackCase.getIpAddress() != null && loopbackCase.getIpPrefix() != null) {\r
-                loopbackCase.setBvi(true);\r
-                LOG.trace("Creating loopback BVI interface: {} for VPP router port: {}.", loopbackCase, port);\r
-            }\r
-\r
-        } else {\r
-            LOG.warn("IpAddress for loopback port: {} was not set.", port);\r
-        }\r
-        return loopbackCase.build();\r
-    }\r
-\r
-    /**\r
-     * If Qrouter (L3 Agent) is in use, any of Openstack neutron routers is not going be mapped\r
-     * to ODL neutron.\r
-     */\r
-    private boolean isValidQRouterPort(Port port) {\r
-        Optional<Router> optRouter = getRouterOptional(port);\r
-        return !optRouter.isPresent() && port.getDeviceOwner().contains(ROUTER_OWNER) && port.getMacAddress() != null;\r
-    }\r
-\r
-    private boolean isValidVppRouterPort(Port port) {\r
-        Optional<Router> optRouter = getRouterOptional(port);\r
-        return optRouter.isPresent() && port.getDeviceOwner().contains(ROUTER_OWNER) && port.getMacAddress() != null;\r
-    }\r
-\r
-    private Optional<Router> getRouterOptional(Port port) {\r
-        if (Strings.isNullOrEmpty(port.getDeviceId())) {\r
-            return Optional.absent();\r
-        }\r
-        RouterKey routerKey = null;\r
-        try {\r
-            routerKey = new RouterKey(new Uuid(port.getDeviceId()));\r
-        } catch (IllegalArgumentException e) {\r
-            // port.getDeviceId() may not match Uuid.PATTERN_CONSTANTS\r
-            return Optional.absent();\r
-        }\r
-        InstanceIdentifier<Router> routerIid =\r
-                InstanceIdentifier.builder(Neutron.class).child(Routers.class).child(Router.class, routerKey).build();\r
-        Optional<Router> optRouter = syncedChain.readFromDs(LogicalDatastoreType.CONFIGURATION, routerIid);\r
-        return optRouter;\r
-    }\r
-\r
-    public static Optional<FixedIps> resolveFirstFixedIps(Port port) {\r
-        List<FixedIps> fixedIps = port.getFixedIps();\r
-        if (fixedIps != null && !fixedIps.isEmpty()) {\r
-            return Optional.of(fixedIps.get(0));\r
-        }\r
-        return Optional.absent();\r
-    }\r
-\r
-    private String createPortName(Uuid portUuid) {\r
-        String tapPortName;\r
-        String uuid = portUuid.getValue();\r
-        if (uuid != null && uuid.length() >= 12) {\r
-            tapPortName = TAP_PORT_NAME_PREFIX + uuid.substring(0, 11);\r
-        } else {\r
-            tapPortName = TAP_PORT_NAME_PREFIX + uuid;\r
-        }\r
-        return tapPortName;\r
-    }\r
-\r
-    private String createQRouterPortName(Uuid portUuid) {\r
-        String tapPortName;\r
-        String uuid = portUuid.getValue();\r
-        if (uuid != null && uuid.length() >= 12) {\r
-            tapPortName = RT_PORT_NAME_PREFIX + uuid.substring(0, 11);\r
-        } else {\r
-            tapPortName = RT_PORT_NAME_PREFIX + uuid;\r
-        }\r
-        return tapPortName;\r
-    }\r
-\r
-    private InstanceIdentifier<VppEndpoint> createVppEndpointIid(VppEndpointKey vppEpKey) {\r
-        return InstanceIdentifier.builder(Config.class).child(VppEndpoint.class, vppEpKey).build();\r
-    }\r
-\r
-    private InstanceIdentifier<BaseEndpointByPort> createBaseEpByPortIid(Uuid uuid) {\r
-        return createBaseEpByPortIid(new UniqueId(uuid.getValue()));\r
-    }\r
-\r
-    private InstanceIdentifier<BaseEndpointByPort> createBaseEpByPortIid(UniqueId uuid) {\r
-        return InstanceIdentifier.builder(Mappings.class)\r
-            .child(GbpByNeutronMappings.class)\r
-            .child(BaseEndpointsByPorts.class)\r
-            .child(BaseEndpointByPort.class, new BaseEndpointByPortKey(uuid))\r
-            .build();\r
-    }\r
-\r
-    InstanceIdentifier<Port> createWildcartedPortIid() {\r
-        return portsIid().child(Port.class).build();\r
-    }\r
-\r
-    private InstanceIdentifier<Port> createPortIid(UniqueId uuid) {\r
-        return portsIid().child(Port.class, new PortKey(new Uuid(uuid.getValue()))).build();\r
-    }\r
-\r
-    private InstanceIdentifierBuilder<Ports> portsIid() {\r
-        return InstanceIdentifier.builder(Neutron.class).child(Ports.class);\r
-    }\r
-\r
-    @Override\r
-    public void onTransactionChainFailed(TransactionChain<?, ?> chain, AsyncTransaction<?, ?> transaction,\r
-            Throwable cause) {\r
-        LOG.error("Transaction chain failed. {} \nTransaction which caused the chain to fail {}", cause.getMessage(),\r
-                transaction, cause);\r
-        syncedChain.closeChain();\r
-        this.syncedChain = new SyncedChain(Preconditions.checkNotNull(dataBroker.createTransactionChain(this)));\r
-    }\r
-\r
-    @Override\r
-    public void onTransactionChainSuccessful(TransactionChain<?, ?> chain) {\r
-        LOG.trace("Transaction chain was successful. {}", chain);\r
-    }\r
-\r
-    private <T> List<T> nullToEmpty(@Nullable List<T> list) {\r
-        return list == null ? Collections.emptyList() : list;\r
-    }\r
-}\r
+/*
+ * Copyright (c) 2016 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.groupbasedpolicy.neutron.vpp.mapper.processors;
+
+import java.util.Collections;
+import java.util.List;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
+import org.opendaylight.controller.md.sal.common.api.data.AsyncTransaction;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.controller.md.sal.common.api.data.TransactionChain;
+import org.opendaylight.controller.md.sal.common.api.data.TransactionChainListener;
+import org.opendaylight.groupbasedpolicy.util.DataStoreHelper;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress;
+import org.opendaylight.groupbasedpolicy.util.SyncedChain;
+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.inet.types.rev130715.Ipv4Prefix;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.PhysAddress;
+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.common.rev140421.UniqueId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.neutron.gbp.mapper.rev150513.Mappings;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.neutron.gbp.mapper.rev150513.mappings.GbpByNeutronMappings;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.neutron.gbp.mapper.rev150513.mappings.gbp.by.neutron.mappings.BaseEndpointsByPorts;
+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.base.endpoints.by.ports.BaseEndpointByPortKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.vpp_renderer.rev160425.Config;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.vpp_renderer.rev160425.ExcludeFromPolicy;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.vpp_renderer.rev160425.ExcludeFromPolicyBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.vpp_renderer.rev160425._interface.attributes._interface.type.choice.LoopbackCase;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.vpp_renderer.rev160425._interface.attributes._interface.type.choice.LoopbackCaseBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.vpp_renderer.rev160425._interface.attributes._interface.type.choice.TapCase;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.vpp_renderer.rev160425._interface.attributes._interface.type.choice.TapCaseBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.vpp_renderer.rev160425._interface.attributes._interface.type.choice.VhostUserCaseBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.vpp_renderer.rev160425.config.VppEndpoint;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.vpp_renderer.rev160425.config.VppEndpointBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.vpp_renderer.rev160425.config.VppEndpointKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.binding.rev150712.PortBindingExtension;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.binding.rev150712.binding.attributes.VifDetails;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.l3.rev150712.routers.attributes.Routers;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.l3.rev150712.routers.attributes.routers.Router;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.l3.rev150712.routers.attributes.routers.RouterKey;
+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.ports.rev150712.ports.attributes.ports.PortKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.portsecurity.rev150712.PortSecurityExtension;
+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;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.subnets.rev150712.subnets.attributes.subnets.Subnet;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.subnets.rev150712.subnets.attributes.subnets.SubnetKey;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.InstanceIdentifierBuilder;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.annotations.VisibleForTesting;
+import com.google.common.base.Optional;
+import com.google.common.base.Preconditions;
+import com.google.common.base.Strings;
+
+public class PortHandler implements TransactionChainListener {
+
+    private static final Logger LOG = LoggerFactory.getLogger(PortHandler.class);
+
+    private static final String COMPUTE_OWNER = "compute";
+    private static final String DHCP_OWNER = "dhcp";
+    static final String ROUTER_OWNER = "network:router_interface";
+    private static final String[] SUPPORTED_DEVICE_OWNERS = {COMPUTE_OWNER, DHCP_OWNER, ROUTER_OWNER};
+    private static final String VHOST_USER = "vhostuser";
+    private static final String UNBOUND = "unbound";
+    private static final String VPP_INTERFACE_NAME_PREFIX = "neutron_port_";
+    private static final String TAP_PORT_NAME_PREFIX = "tap";
+    private static final String RT_PORT_NAME_PREFIX = "qr-";
+    private static final String VHOST_SOCKET_KEY = "vhostuser_socket";
+    static final String DEFAULT_NODE = "default";
+
+    private final NodeId routingNode;
+    private SyncedChain syncedChain;
+    private DataBroker dataBroker;
+
+    PortHandler(DataBroker dataBroker, NodeId routingNodeId) {
+        this.dataBroker = dataBroker;
+        this.routingNode = routingNodeId;
+        this.syncedChain = new SyncedChain(Preconditions.checkNotNull(dataBroker.createTransactionChain(this)));
+    }
+
+    void processCreated(Port port) {
+        Optional<BaseEndpointByPort> optBaseEpByPort =
+                syncedChain.readFromDs(LogicalDatastoreType.OPERATIONAL, createBaseEpByPortIid(port.getUuid()));
+        if (!optBaseEpByPort.isPresent()) {
+            return;
+        }
+        processCreatedData(port, optBaseEpByPort.get());
+    }
+
+    void processCreated(BaseEndpointByPort bebp) {
+        Optional<Port> optPort =
+                syncedChain.readFromDs(LogicalDatastoreType.CONFIGURATION, createPortIid(bebp.getPortId()));
+        if (!optPort.isPresent()) {
+            return;
+        }
+        processCreatedData(optPort.get(), bebp);
+    }
+
+    @VisibleForTesting
+    void processCreatedData(Port port, BaseEndpointByPort bebp) {
+        if (isValidVhostUser(port)
+                // this is a hack for vpp router port
+                // Openstack does not send binding details yet
+                || isValidVppRouterPort(port)) {
+            VppEndpoint vppEp = buildVppEndpoint(port, bebp);
+            if (vppEp == null) {
+                LOG.warn("Cannot create vpp-endpoint from neutron port {}", port);
+                return;
+            }
+            writeVppEndpoint(createVppEndpointIid(vppEp.getKey()), vppEp);
+            LOG.debug("Created vpp-endpoint {}", vppEp);
+        }
+    }
+
+    private boolean isValidVhostUser(Port port) {
+        PortBindingExtension portBindingExt = port.getAugmentation(PortBindingExtension.class);
+        if (portBindingExt != null) {
+            String vifType = portBindingExt.getVifType();
+            String deviceOwner = port.getDeviceOwner();
+            if (vifType != null && deviceOwner != null) {
+                if (vifType.contains(VHOST_USER)) {
+                    for (String supportedDeviceOwner : SUPPORTED_DEVICE_OWNERS) {
+                        if (deviceOwner.contains(supportedDeviceOwner)) {
+                            return true;
+                        }
+                    }
+                }
+            }
+        }
+        return false;
+    }
+
+    void processUpdated(Port original, Port delta) {
+        if (!isUpdateNeeded(original, delta)) {
+            LOG.trace("Port update skipped, port didn`t change. before {}, after: {}", original, delta);
+            return;
+        }
+
+        LOG.trace("Updating port before: {}, after: {}", original, delta);
+        if (isValidVhostUser(original)) {
+            Optional<BaseEndpointByPort> optBebp =
+                    syncedChain.readFromDs(LogicalDatastoreType.OPERATIONAL, createBaseEpByPortIid(original.getUuid()));
+            if (!optBebp.isPresent()) {
+                return;
+            }
+            LOG.trace("Updating port - deleting old port {}", optBebp.get().getPortId());
+            processDeleted(optBebp.get());
+        }
+        LOG.trace("Updating port - creating new port {}", delta.getUuid());
+        processCreated(delta);
+    }
+
+    private boolean isUpdateNeeded(final Port oldPort, final Port newPort) {
+        // TODO fix this to better support update of ports for VPP
+        final PortBindingExtension oldPortAugmentation = oldPort.getAugmentation(PortBindingExtension.class);
+        final PortBindingExtension newPortAugmentation = newPort.getAugmentation(PortBindingExtension.class);
+
+        if (newPortAugmentation == null) {
+            LOG.trace("Port {} is no longer a vhost type port, updating port...");
+            return true;
+        }
+
+        final String oldDeviceOwner = oldPort.getDeviceOwner();
+        final String oldVifType = oldPortAugmentation.getVifType();
+        final String newDeviceOwner = newPort.getDeviceOwner();
+        final String newVifType = newPortAugmentation.getVifType();
+
+        // TODO potential bug here
+        // Temporary change for Openstack Mitaka: If old neutron-binding:vif-type is vhost, new one
+        // is unbound and
+        // device owner is ROUTER_OWNER, skip update. Openstack (or ml2) sometimes sends router
+        // update messages in
+        // incorrect order which causes unwanted port removal
+        if (oldVifType.equals(VHOST_USER) && newVifType.equals(UNBOUND) && oldDeviceOwner != null
+                && ROUTER_OWNER.equals(oldDeviceOwner) && ROUTER_OWNER.equals(newDeviceOwner)) {
+            LOG.warn(
+                    "Port vif-type was updated from vhost to unbound. This update is currently disabled and will be skipped");
+            return false;
+        }
+
+        if (newVifType != null && !newVifType.equals(oldVifType)) {
+            LOG.trace("Vif type changed, old: {} new {}", oldVifType, newVifType);
+            return true;
+        }
+
+        final List<VifDetails> vifDetails = oldPortAugmentation.getVifDetails();
+
+        if (!oldPortAugmentation.getHostId().equals(newPortAugmentation.getHostId())
+                || nullToEmpty(vifDetails).size() != nullToEmpty(newPortAugmentation.getVifDetails()).size()) {
+            return true;
+        }
+
+        for (VifDetails vifDetail : nullToEmpty(vifDetails)) {
+            // check if vhostuser_socket, vhostuser_mode and port_filter are changed
+            if (!newPortAugmentation.getVifDetails().contains(vifDetail))
+                return true;
+        }
+        return false;
+    }
+
+    void processDeleted(BaseEndpointByPort bebp) {
+        LOG.trace("Deleting vpp-endpoint by BaseEndpointByPort {}", bebp);
+        VppEndpointKey vppEpKey = new VppEndpointKey(bebp.getAddress(), bebp.getAddressType(), bebp.getContextId(),
+                bebp.getContextType());
+        InstanceIdentifier<VppEndpoint> vppEpIid = createVppEndpointIid(vppEpKey);
+        Optional<VppEndpoint> readVppEp = syncedChain.readFromDs(LogicalDatastoreType.CONFIGURATION, vppEpIid);
+        if (readVppEp.isPresent()) {
+            writeVppEndpoint(vppEpIid, null);
+            LOG.debug("Deleted vpp-endpoint {}", vppEpKey);
+        }
+    }
+
+    private synchronized void writeVppEndpoint(InstanceIdentifier<VppEndpoint> vppEpIid, VppEndpoint vppEp) {
+        WriteTransaction wTx = syncedChain.newWriteOnlyTransaction();
+        if (vppEp != null) {
+            wTx.put(LogicalDatastoreType.CONFIGURATION, vppEpIid, vppEp, true);
+        } else {
+            wTx.delete(LogicalDatastoreType.CONFIGURATION, vppEpIid);
+        }
+        syncedChain.submitNow(wTx);
+    }
+
+    @VisibleForTesting
+    VppEndpoint buildVppEndpoint(Port port, BaseEndpointByPort bebp) {
+        PortBindingExtension portBinding = port.getAugmentation(PortBindingExtension.class);
+        ExcludeFromPolicy excludeFromPolicy = new ExcludeFromPolicyBuilder().setExcludeFromPolicy(true).build();
+        VppEndpointBuilder vppEpBuilder = new VppEndpointBuilder().setDescription("neutron port")
+            .setContextId(bebp.getContextId())
+            .setContextType(bebp.getContextType())
+            .setAddress(bebp.getAddress())
+            .setAddressType(bebp.getAddressType())
+            .setVppInterfaceName(VPP_INTERFACE_NAME_PREFIX + bebp.getPortId().getValue())
+            .setVppNodeId(new NodeId(portBinding.getHostId()));
+
+        if (port.getDeviceOwner().contains(COMPUTE_OWNER)) {
+            vppEpBuilder.setInterfaceTypeChoice(
+                    new VhostUserCaseBuilder().setSocket(getSocketFromPortBinding(portBinding)).build());
+            Optional<PortSecurityExtension> portSecurity =
+                    Optional.fromNullable(port.getAugmentation(PortSecurityExtension.class));
+            if (portSecurity.isPresent() && !portSecurity.get().isPortSecurityEnabled()) {
+                vppEpBuilder.addAugmentation(ExcludeFromPolicy.class, excludeFromPolicy);
+            }
+
+        } else if (port.getDeviceOwner().contains(DHCP_OWNER) && port.getMacAddress() != null) {
+            IpAddress dhcpServerIpAddress = port.getFixedIps().stream().findFirst().isPresent() ?
+                port.getFixedIps().stream().findFirst().get().getIpAddress() : null;
+            TapCase tapCase = new TapCaseBuilder().setPhysicalAddress(new PhysAddress(port.getMacAddress().getValue()))
+                .setName(createPortName(port.getUuid()))
+                .setDhcpServerAddress(dhcpServerIpAddress)
+                .build();
+            vppEpBuilder.setInterfaceTypeChoice(tapCase);
+
+        } else if (isValidQRouterPort(port)) {
+            TapCase tapCase = new TapCaseBuilder().setPhysicalAddress(new PhysAddress(port.getMacAddress().getValue()))
+                .setName(createQRouterPortName(port.getUuid()))
+                .build();
+            vppEpBuilder.setInterfaceTypeChoice(tapCase);
+            vppEpBuilder.addAugmentation(ExcludeFromPolicy.class, excludeFromPolicy);
+
+        } else if (isValidVppRouterPort(port)) {
+            if (!DEFAULT_NODE.equals(routingNode.getValue())) {
+                LOG.warn(
+                        "Host-id changed by ODL for port {}. This is a supplementary workaround for choosing a routing node.",
+                        port);
+                vppEpBuilder.setVppNodeId(routingNode);
+            } else if (port.getDeviceId() != null) {
+                LOG.debug("Resolving host-id for unbound router port {}", port.getUuid());
+                Optional<Ports> optPorts = syncedChain.readFromDs(LogicalDatastoreType.CONFIGURATION,
+                        InstanceIdentifier.builder(Neutron.class).child(Ports.class).build());
+                if (optPorts.isPresent() && optPorts.get().getPort() != null) {
+                    java.util.Optional<Port> optPortOnTheSameNode = optPorts.get()
+                        .getPort()
+                        .stream()
+                        .filter(p -> !p.getUuid().equals(port.getUuid()))
+                        .filter(p -> p.getAugmentation(PortBindingExtension.class) != null)
+                        .filter(p -> p.getDeviceOwner().contains(DHCP_OWNER))
+                        .findFirst();
+                    if (optPortOnTheSameNode.isPresent()) {
+                        PortBindingExtension binding =
+                                optPortOnTheSameNode.get().getAugmentation(PortBindingExtension.class);
+                        if (binding != null && binding.getHostId() != null) {
+                            vppEpBuilder.setVppNodeId(new NodeId(binding.getHostId()));
+                        } else {
+                            LOG.warn("Cannot resolve location of router-port {}", port.getUuid());
+                            return null;
+                        }
+                    }
+                }
+            }
+            vppEpBuilder.addAugmentation(ExcludeFromPolicy.class, excludeFromPolicy);
+            vppEpBuilder.setInterfaceTypeChoice(getLoopbackCase(port));
+        }
+        return vppEpBuilder.build();
+    }
+
+    private String getSocketFromPortBinding(@Nonnull PortBindingExtension portBindingExtension) {
+        List<VifDetails> vifDetails = nullToEmpty(portBindingExtension.getVifDetails());
+
+        for (VifDetails detail : vifDetails) {
+            if (VHOST_SOCKET_KEY.equalsIgnoreCase(detail.getDetailsKey())) {
+                return detail.getValue();
+            }
+        }
+        return null;
+    }
+
+    private LoopbackCase getLoopbackCase(Port port) {
+        LoopbackCaseBuilder loopbackCase =
+                new LoopbackCaseBuilder().setPhysAddress(new PhysAddress(port.getMacAddress().getValue()));
+        Optional<FixedIps> fixedIpsOptional = resolveFirstFixedIps(port);
+        if (fixedIpsOptional.isPresent() && fixedIpsOptional.get().getIpAddress() != null) {
+            loopbackCase.setIpAddress(fixedIpsOptional.get().getIpAddress());
+            Optional<Subnet> subnetOptional = syncedChain.readFromDs(LogicalDatastoreType.CONFIGURATION,
+                    InstanceIdentifier.builder(Neutron.class)
+                        .child(Subnets.class)
+                        .child(Subnet.class, new SubnetKey(fixedIpsOptional.get().getSubnetId()))
+                        .build());
+            if (subnetOptional.isPresent()) {
+                Ipv4Prefix ipv4Prefix = subnetOptional.get().getCidr().getIpv4Prefix();
+                loopbackCase.setIpPrefix(new IpPrefix(ipv4Prefix));
+            } else {
+                LOG.warn("IpPrefix for loopback port: {} was not set.", port);
+            }
+            if (loopbackCase.getIpAddress() != null && loopbackCase.getIpPrefix() != null) {
+                loopbackCase.setBvi(true);
+                LOG.trace("Creating loopback BVI interface: {} for VPP router port: {}.", loopbackCase, port);
+            }
+
+        } else {
+            LOG.warn("IpAddress for loopback port: {} was not set.", port);
+        }
+        return loopbackCase.build();
+    }
+
+    /**
+     * If Qrouter (L3 Agent) is in use, any of Openstack neutron routers is not going be mapped
+     * to ODL neutron.
+     */
+    private boolean isValidQRouterPort(Port port) {
+        Optional<Router> optRouter = getRouterOptional(port);
+        return !optRouter.isPresent() && port.getDeviceOwner().contains(ROUTER_OWNER) && port.getMacAddress() != null;
+    }
+
+    private boolean isValidVppRouterPort(Port port) {
+        Optional<Router> optRouter = getRouterOptional(port);
+        return optRouter.isPresent() && port.getDeviceOwner().contains(ROUTER_OWNER) && port.getMacAddress() != null;
+    }
+
+    private Optional<Router> getRouterOptional(Port port) {
+        if (Strings.isNullOrEmpty(port.getDeviceId())) {
+            return Optional.absent();
+        }
+        RouterKey routerKey = null;
+        try {
+            routerKey = new RouterKey(new Uuid(port.getDeviceId()));
+        } catch (IllegalArgumentException e) {
+            // port.getDeviceId() may not match Uuid.PATTERN_CONSTANTS
+            return Optional.absent();
+        }
+        InstanceIdentifier<Router> routerIid =
+                InstanceIdentifier.builder(Neutron.class).child(Routers.class).child(Router.class, routerKey).build();
+        Optional<Router> optRouter = syncedChain.readFromDs(LogicalDatastoreType.CONFIGURATION, routerIid);
+        return optRouter;
+    }
+
+    public static Optional<FixedIps> resolveFirstFixedIps(Port port) {
+        List<FixedIps> fixedIps = port.getFixedIps();
+        if (fixedIps != null && !fixedIps.isEmpty()) {
+            return Optional.of(fixedIps.get(0));
+        }
+        return Optional.absent();
+    }
+
+    private String createPortName(Uuid portUuid) {
+        String tapPortName;
+        String uuid = portUuid.getValue();
+        if (uuid != null && uuid.length() >= 12) {
+            tapPortName = TAP_PORT_NAME_PREFIX + uuid.substring(0, 11);
+        } else {
+            tapPortName = TAP_PORT_NAME_PREFIX + uuid;
+        }
+        return tapPortName;
+    }
+
+    private String createQRouterPortName(Uuid portUuid) {
+        String tapPortName;
+        String uuid = portUuid.getValue();
+        if (uuid != null && uuid.length() >= 12) {
+            tapPortName = RT_PORT_NAME_PREFIX + uuid.substring(0, 11);
+        } else {
+            tapPortName = RT_PORT_NAME_PREFIX + uuid;
+        }
+        return tapPortName;
+    }
+
+    private InstanceIdentifier<VppEndpoint> createVppEndpointIid(VppEndpointKey vppEpKey) {
+        return InstanceIdentifier.builder(Config.class).child(VppEndpoint.class, vppEpKey).build();
+    }
+
+    private InstanceIdentifier<BaseEndpointByPort> createBaseEpByPortIid(Uuid uuid) {
+        return createBaseEpByPortIid(new UniqueId(uuid.getValue()));
+    }
+
+    private InstanceIdentifier<BaseEndpointByPort> createBaseEpByPortIid(UniqueId uuid) {
+        return InstanceIdentifier.builder(Mappings.class)
+            .child(GbpByNeutronMappings.class)
+            .child(BaseEndpointsByPorts.class)
+            .child(BaseEndpointByPort.class, new BaseEndpointByPortKey(uuid))
+            .build();
+    }
+
+    InstanceIdentifier<Port> createWildcartedPortIid() {
+        return portsIid().child(Port.class).build();
+    }
+
+    private InstanceIdentifier<Port> createPortIid(UniqueId uuid) {
+        return portsIid().child(Port.class, new PortKey(new Uuid(uuid.getValue()))).build();
+    }
+
+    private InstanceIdentifierBuilder<Ports> portsIid() {
+        return InstanceIdentifier.builder(Neutron.class).child(Ports.class);
+    }
+
+    @Override
+    public void onTransactionChainFailed(TransactionChain<?, ?> chain, AsyncTransaction<?, ?> transaction,
+            Throwable cause) {
+        LOG.error("Transaction chain failed. {} \nTransaction which caused the chain to fail {}", cause.getMessage(),
+                transaction, cause);
+        syncedChain.closeChain();
+        this.syncedChain = new SyncedChain(Preconditions.checkNotNull(dataBroker.createTransactionChain(this)));
+    }
+
+    @Override
+    public void onTransactionChainSuccessful(TransactionChain<?, ?> chain) {
+        LOG.trace("Transaction chain was successful. {}", chain);
+    }
+
+    private <T> List<T> nullToEmpty(@Nullable List<T> list) {
+        return list == null ? Collections.emptyList() : list;
+    }
+}