X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?a=blobdiff_plain;f=neutron-vpp-mapper%2Fsrc%2Fmain%2Fjava%2Forg%2Fopendaylight%2Fgroupbasedpolicy%2Fneutron%2Fvpp%2Fmapper%2Fprocessors%2FPortHandler.java;h=11d7df4f8f67b7e462fb70248c68f768e5ebe848;hb=c6106efb538b33eff3e4aa133deb08fcfa0b41e3;hp=3c25a8c913e0b9b56c8bd3a157bc08105b0b2501;hpb=00aa434480520b9b204574ababc4387038700555;p=groupbasedpolicy.git diff --git a/neutron-vpp-mapper/src/main/java/org/opendaylight/groupbasedpolicy/neutron/vpp/mapper/processors/PortHandler.java b/neutron-vpp-mapper/src/main/java/org/opendaylight/groupbasedpolicy/neutron/vpp/mapper/processors/PortHandler.java index 3c25a8c91..11d7df4f8 100644 --- a/neutron-vpp-mapper/src/main/java/org/opendaylight/groupbasedpolicy/neutron/vpp/mapper/processors/PortHandler.java +++ b/neutron-vpp-mapper/src/main/java/org/opendaylight/groupbasedpolicy/neutron/vpp/mapper/processors/PortHandler.java @@ -21,7 +21,6 @@ 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.neutron.vpp.mapper.SocketInfo; import org.opendaylight.groupbasedpolicy.util.DataStoreHelper; 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; @@ -34,6 +33,8 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.neutron.gb 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; @@ -63,27 +64,32 @@ import org.slf4j.LoggerFactory; import com.google.common.annotations.VisibleForTesting; import com.google.common.base.Optional; +import com.google.common.base.Strings; +import javax.annotation.Nonnull; public class PortHandler implements TransactionChainListener { - private static final Logger LOG = LoggerFactory.getLogger(MappingProvider.class); + private static final Logger LOG = LoggerFactory.getLogger(PortHandler.class); private static final String COMPUTE_OWNER = "compute"; private static final String DHCP_OWNER = "dhcp"; - private static final String ROUTER_OWNER = "network:router_interface"; + 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 BindingTransactionChain transactionChain; private DataBroker dataBroker; - private SocketInfo socketInfo; - PortHandler(DataBroker dataBroker, SocketInfo socketInfo) { + PortHandler(DataBroker dataBroker, NodeId routingNodeId) { this.dataBroker = dataBroker; - this.socketInfo = socketInfo; + this.routingNode = routingNodeId; transactionChain = this.dataBroker.createTransactionChain(this); } @@ -111,8 +117,15 @@ public class PortHandler implements TransactionChainListener { @VisibleForTesting void processCreatedData(Port port, BaseEndpointByPort bebp) { - if (isValidVhostUser(port)) { + 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); } @@ -158,18 +171,38 @@ public class PortHandler implements TransactionChainListener { processCreated(delta); } - private boolean isUpdateNeeded(Port oldPort, Port newPort) { + private boolean isUpdateNeeded(final Port oldPort, final Port newPort) { //TODO fix this to better support update of ports for VPP - PortBindingExtension oldPortAugmentation = oldPort.getAugmentation(PortBindingExtension.class); - PortBindingExtension newPortAugmentation = newPort.getAugmentation(PortBindingExtension.class); - - List vifDetails = oldPortAugmentation.getVifDetails(); + 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 = oldPortAugmentation.getVifDetails(); + if (!oldPortAugmentation.getHostId().equals(newPortAugmentation.getHostId()) || nullToEmpty(vifDetails).size() != nullToEmpty(newPortAugmentation.getVifDetails()).size()) { return true; @@ -218,8 +251,8 @@ public class PortHandler implements TransactionChainListener { .setVppInterfaceName(VPP_INTERFACE_NAME_PREFIX + bebp.getPortId().getValue()) .setVppNodeId(new NodeId(portBinding.getHostId())); if (port.getDeviceOwner().contains(COMPUTE_OWNER)) { - String socket = socketInfo.getSocketPath() + socketInfo.getSocketPrefix() + bebp.getPortId().getValue(); - vppEpBuilder.setInterfaceTypeChoice(new VhostUserCaseBuilder().setSocket(socket).build()); + vppEpBuilder.setInterfaceTypeChoice( + new VhostUserCaseBuilder().setSocket(getSocketFromPortBinding(portBinding)).build()); } else if (port.getDeviceOwner().contains(DHCP_OWNER) && port.getMacAddress() != null) { TapCase tapCase = new TapCaseBuilder().setPhysicalAddress(new PhysAddress(port.getMacAddress().getValue())) .setName(createPortName(port.getUuid())) @@ -230,12 +263,58 @@ public class PortHandler implements TransactionChainListener { .setName(createQRouterPortName(port.getUuid())) .build(); vppEpBuilder.setInterfaceTypeChoice(tapCase); + vppEpBuilder.addAugmentation(ExcludeFromPolicy.class, + new ExcludeFromPolicyBuilder().setExcludeFromPolicy(true).build()); } 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()); + ReadOnlyTransaction readTx = dataBroker.newReadOnlyTransaction(); + Optional optPorts = DataStoreHelper.readFromDs(LogicalDatastoreType.CONFIGURATION, + InstanceIdentifier.builder(Neutron.class).child(Ports.class).build(), readTx); + readTx.close(); + if (optPorts.isPresent() && optPorts.get().getPort() != null) { + java.util.Optional 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, + new ExcludeFromPolicyBuilder().setExcludeFromPolicy(true).build()); vppEpBuilder.setInterfaceTypeChoice(getLoopbackCase(port)); } return vppEpBuilder.build(); } + private String getSocketFromPortBinding(@Nonnull PortBindingExtension portBindingExtension) { + List 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())); @@ -283,6 +362,9 @@ public class PortHandler implements TransactionChainListener { } private Optional getRouterOptional(Port port) { + if (Strings.isNullOrEmpty(port.getDeviceId())) { + return Optional.absent(); + } ReadOnlyTransaction rTx = transactionChain.newReadOnlyTransaction(); InstanceIdentifier routerIid = InstanceIdentifier.builder(Neutron.class) .child(Routers.class)