\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.Nullable;\r
+\r
import org.opendaylight.controller.md.sal.binding.api.BindingTransactionChain;\r
import org.opendaylight.controller.md.sal.binding.api.DataBroker;\r
import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction;\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._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.groupbasedpolicy.vpp_renderer.rev160425.config.vpp.endpoint._interface.type.choice.LoopbackCase;\r
-import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.vpp_renderer.rev160425.config.vpp.endpoint._interface.type.choice.LoopbackCaseBuilder;\r
-import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.vpp_renderer.rev160425.config.vpp.endpoint._interface.type.choice.TapCase;\r
-import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.vpp_renderer.rev160425.config.vpp.endpoint._interface.type.choice.TapCaseBuilder;\r
-import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.vpp_renderer.rev160425.config.vpp.endpoint._interface.type.choice.VhostUserCaseBuilder;\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.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.NetworkTopology;\r
import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;\r
-import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.TopologyId;\r
-import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.Topology;\r
-import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.TopologyKey;\r
-import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;\r
-import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.NodeKey;\r
import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;\r
import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.InstanceIdentifierBuilder;\r
import org.slf4j.Logger;\r
import com.google.common.annotations.VisibleForTesting;\r
import com.google.common.base.Optional;\r
\r
-import java.util.List;\r
-\r
public class PortHandler implements TransactionChainListener {\r
\r
- private static final Logger LOG = LoggerFactory.getLogger(MappingProvider.class);\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
private 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 NETCONF_TOPOLOGY_ID = "topology-netconf";\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
}\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
ReadOnlyTransaction rTx = transactionChain.newReadOnlyTransaction();\r
Optional<BaseEndpointByPort> optBebp = DataStoreHelper.readFromDs(LogicalDatastoreType.OPERATIONAL,\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 is unbound and\r
+ // device owner is ROUTER_OWNER, skip update. Openstack (or ml2) sometimes sends router 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("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
.setAddress(bebp.getAddress())\r
.setAddressType(bebp.getAddressType())\r
.setVppInterfaceName(VPP_INTERFACE_NAME_PREFIX + bebp.getPortId().getValue())\r
- .setVppNodePath(createNodeIid(new NodeId(portBinding.getHostId())));\r
+ .setVppNodeId(new NodeId(portBinding.getHostId()));\r
if (port.getDeviceOwner().contains(COMPUTE_OWNER)) {\r
String socket = socketInfo.getSocketPath() + socketInfo.getSocketPrefix() + bebp.getPortId().getValue();\r
vppEpBuilder.setInterfaceTypeChoice(new VhostUserCaseBuilder().setSocket(socket).build());\r
return tapPortName;\r
}\r
\r
- private InstanceIdentifier<Node> createNodeIid(NodeId nodeId) {\r
- return InstanceIdentifier.builder(NetworkTopology.class)\r
- .child(Topology.class, new TopologyKey(new TopologyId(NETCONF_TOPOLOGY_ID)))\r
- .child(Node.class, new NodeKey(nodeId))\r
- .build();\r
- }\r
-\r
private InstanceIdentifier<VppEndpoint> createVppEndpointIid(VppEndpointKey vppEpKey) {\r
return InstanceIdentifier.builder(Config.class).child(VppEndpoint.class, vppEpKey).build();\r
}\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