package org.opendaylight.netvirt.openstack.netvirt;
+import java.net.InetAddress;
import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+import org.apache.commons.lang3.tuple.Pair;
import org.opendaylight.netvirt.openstack.netvirt.api.Action;
import org.opendaylight.netvirt.openstack.netvirt.api.BridgeConfigurationManager;
import org.opendaylight.netvirt.openstack.netvirt.api.ConfigurationService;
import org.opendaylight.netvirt.openstack.netvirt.api.Constants;
import org.opendaylight.netvirt.openstack.netvirt.api.EventDispatcher;
+import org.opendaylight.netvirt.openstack.netvirt.api.L2ForwardingProvider;
import org.opendaylight.netvirt.openstack.netvirt.api.NetworkingProviderManager;
import org.opendaylight.netvirt.openstack.netvirt.api.NodeCacheListener;
import org.opendaylight.netvirt.openstack.netvirt.api.NodeCacheManager;
import org.opendaylight.netvirt.openstack.netvirt.api.TenantNetworkManager;
import org.opendaylight.netvirt.openstack.netvirt.translator.NeutronNetwork;
import org.opendaylight.netvirt.openstack.netvirt.translator.NeutronPort;
+import org.opendaylight.netvirt.openstack.netvirt.translator.crud.INeutronNetworkCRUD;
import org.opendaylight.netvirt.openstack.netvirt.impl.DistributedArpService;
import org.opendaylight.netvirt.openstack.netvirt.impl.NeutronL3Adapter;
import org.opendaylight.netvirt.utils.servicehelper.ServiceHelper;
+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.params.xml.ns.yang.ovsdb.rev150105.InterfaceTypeVxlan;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbBridgeAugmentation;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbNodeAugmentation;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbTerminationPointAugmentation;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.port._interface.attributes.Options;
import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.node.TerminationPoint;
import org.opendaylight.yangtools.yang.binding.DataObject;
private volatile NeutronL3Adapter neutronL3Adapter;
private volatile DistributedArpService distributedArpService;
private volatile NodeCacheManager nodeCacheManager;
+ private volatile INeutronNetworkCRUD neutronNetworkCache;
private volatile OvsdbInventoryService ovsdbInventoryService;
private volatile Southbound southbound;
private volatile VLANProvider vlanProvider;
+ private volatile L2ForwardingProvider l2ForwardingProvider;
private SouthboundEvent.Type ovsdbTypeToSouthboundEventType(OvsdbType ovsdbType) {
SouthboundEvent.Type type = SouthboundEvent.Type.NODE;
@Override
public void ovsdbUpdate(Node node, DataObject resourceAugmentationData, OvsdbType ovsdbType, Action action) {
- LOG.info("Received ovsdbUpdate for : {} with action : {} for the OVS node : {}"
- +"Resource Data : {}", ovsdbType, action, node, resourceAugmentationData);
+ LOG.debug("Received ovsdbUpdate for : {} with action : {} for the OVS node : {} Resource Data : {}",
+ ovsdbType, action, node, resourceAugmentationData);
enqueueEvent(new SouthboundEvent(node, resourceAugmentationData,
ovsdbTypeToSouthboundEventType(ovsdbType), action));
}
LOG.debug("No tenant network found on node : {} for interface: {}", node, tp);
}
if (action.equals(Action.UPDATE)) {
- distributedArpService.processInterfaceEvent(node, tp, network, action);
+ distributedArpService.processInterfaceEvent(node, tp, network, false, action);
}
- neutronL3Adapter.handleInterfaceEvent(node, tp, network, Action.UPDATE);
+ neutronL3Adapter.handleInterfaceEvent(node, tp, network, action);
+ }
+ /**
+ * Get dpid from node.
+ *
+ * @param node the {@link Node Node} of interest in the notification
+ * @return dpid value
+ */
+ private Long getDpidForIntegrationBridge(Node node) {
+ // Check if node is integration bridge; and only then return its dpid
+ if (southbound.getBridge(node, configurationService.getIntegrationBridgeName()) != null) {
+ return southbound.getDataPathId(node);
+ }
+ return null;
+ }
+
+ /**
+ * Returns true, if the port is migrated else false.
+ *
+ * @param node the node associated with Neutron Port.
+ * @param neutronPort the port details.
+ * @return boolean true, if the port is migrated else false.
+ */
+ private boolean isMigratedPort(Node node, NeutronPort neutronPort) {
+ boolean isMigratedPort = false;
+ final Long dpId = getDpidForIntegrationBridge(node);
+ final Pair<Long, Uuid> nodeDpIdPair = neutronL3Adapter.getDpIdOfNeutronPort(neutronPort.getPortUUID());
+ Long dpIdNeutronPort = (nodeDpIdPair == null ? null : nodeDpIdPair.getLeft());
+ if(dpIdNeutronPort != null && !dpIdNeutronPort.equals(dpId)) {
+ isMigratedPort = true;
+ }
+ LOG.trace("isMigratedPort {}, node {}, neutronPort {}, dpIdNeutronPort {} ", isMigratedPort, node.getNodeId(),
+ neutronPort.getMacAddress(), dpIdNeutronPort);
+ return isMigratedPort;
}
private void handleInterfaceDelete (Node node, OvsdbTerminationPointAugmentation intf,
LOG.debug("handleInterfaceDelete: node: <{}>, isLastInstanceOnNode: {}, interface: <{}>",
node, isLastInstanceOnNode, intf);
- distributedArpService.processInterfaceEvent(node, intf, network, Action.DELETE);
- neutronL3Adapter.handleInterfaceEvent(node, intf, network, Action.DELETE);
final NeutronPort neutronPort = tenantNetworkManager.getTenantPort(intf);
+ boolean isMigratedPort = isMigratedPort(node, neutronPort);
+ distributedArpService.processInterfaceEvent(node, intf, network, isMigratedPort, Action.DELETE);
+ neutronL3Adapter.handleInterfaceEvent(node, intf, network, Action.DELETE);
programVLANNetworkFlowProvider(node, intf, network, neutronPort, false);
List<String> phyIfName = bridgeConfigurationManager.getAllPhysicalInterfaceNames(node);
if (isInterfaceOfInterest(intf, phyIfName)) {
// delete tunnel or physical interfaces
networkingProviderManager.getProvider(node).handleInterfaceDelete(network.getProviderNetworkType(),
- network, node, intf, isLastInstanceOnNode);
+ network, node, intf, isLastInstanceOnNode, isMigratedPort);
} else if (network != null) {
// vlan doesn't need a tunnel endpoint
if (!network.getProviderNetworkType().equalsIgnoreCase(NetworkHandler.NETWORK_TYPE_VLAN) &&
return;
}
networkingProviderManager.getProvider(node).handleInterfaceDelete(network.getProviderNetworkType(),
- network, node, intf, isLastInstanceOnNode);
+ network, node, intf, isLastInstanceOnNode, isMigratedPort);
}
+
}
@Override
*/
@Override
public void notifyNode (Node node, Action action) {
- LOG.info("notifyNode : action: {}, Node : {} ", action, node);
+ LOG.trace("notifyNode : action: {}, Node : {} ", action, node);
if ((action == Action.ADD) && (southbound.getBridge(node) != null)) {
networkingProviderManager.getProvider(node).initializeOFFlowRules(node);
}
private void processPortUpdate(Node node, OvsdbTerminationPointAugmentation port, Action action) {
- LOG.debug("processPortUpdate : {} for the Node: {}", port, node);
+ LOG.debug("processPortUpdate : action {}, {} for the Node: {}", action, port, node);
NeutronNetwork network = tenantNetworkManager.getTenantNetwork(port);
if (network != null) {
final NeutronPort neutronPort = tenantNetworkManager.getTenantPort(port);
- if (!network.getRouterExternal()) {
- handleInterfaceUpdate(node, port, action);
- } else if (action != null && action.equals(Action.UPDATE)) {
- programVLANNetworkFlowProvider(node, port, network, neutronPort, true);
+ if (!(Action.UPDATE.equals(action) && isMigratedPort(node, neutronPort))) {
+ if (!network.getRouterExternal()) {
+ handleInterfaceUpdate(node, port, action);
+ } else if (Action.UPDATE.equals(action)) {
+ programVLANNetworkFlowProvider(node, port, network, neutronPort, true);
+ }
+ }
+ } else if (null != port.getInterfaceType() && null != port.getOfport()) {
+ // Filter Vxlan interface request and install table#110 unicast flow (Bug 7392).
+ if(port.getInterfaceType().equals(InterfaceTypeVxlan.class)) {
+ List<Options> optionList = port.getOptions();
+ if (null != optionList && !optionList.isEmpty()) {
+ optionList.stream().filter(option -> isRemoteIp(option)).forEach(option ->
+ handleTunnelOut(node, option.getValue(), port.getOfport()));
+ }
+ }
+ }
+ }
+
+ private boolean isRemoteIp(Options option) {
+ return option.getOption().equals(Constants.TUNNEL_ENDPOINT_KEY_REMOTE);
+ }
+
+ private void handleTunnelOut(Node node, String remoteIp, Long ofPort) {
+ List<Node> nodes = nodeCacheManager.getBridgeNodes();
+ if (null != nodes && !nodes.isEmpty()) {
+ nodes.stream().filter(dstnode -> isDstNode(node, dstnode, remoteIp)).forEach(dstnode ->
+ programTunnelOut(node, dstnode, ofPort));
+ }
+ }
+
+ private boolean isDstNode(Node node, Node dstnode, String remoteIp) {
+ if (!(node.getNodeId().getValue().equals(dstnode.getNodeId().getValue()))) {
+ InetAddress dst = configurationService.getTunnelEndPoint(dstnode);
+ String dstIp = dst.getHostAddress();
+ if (remoteIp.equals(dstIp)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private void programTunnelOut(Node node, Node dstnode, Long ofPort) {
+ List<OvsdbTerminationPointAugmentation> ports = southbound.readTerminationPointAugmentations(dstnode);
+ for (OvsdbTerminationPointAugmentation destport : ports) {
+ NeutronPort neutronPort = tenantNetworkManager.getTenantPort(destport);
+ if (neutronPort != null) {
+ final String networkUUID = neutronPort.getNetworkUUID();
+ NeutronNetwork neutronNetwork = neutronNetworkCache.getNetwork(networkUUID);
+ if (null == neutronNetwork) {
+ neutronNetwork = neutronL3Adapter.getNetworkFromCleanupCache(networkUUID);
+ }
+ final String segmentationId = neutronNetwork != null ? neutronNetwork.getProviderSegmentationID() : null;
+ final String macAddress = neutronPort.getMacAddress();
+ long dpid = getIntegrationBridgeOFDPID(node);
+ if (null != l2ForwardingProvider) {
+ l2ForwardingProvider.programTunnelOut(dpid, segmentationId, ofPort, macAddress, true);
+ }
}
}
}
+ private long getIntegrationBridgeOFDPID(Node node) {
+ long dpid = 0L;
+ if (southbound.getBridgeName(node).equals(configurationService.getIntegrationBridgeName())) {
+ dpid = southbound.getDataPathId(node);
+ }
+ return dpid;
+ }
+
private void programVLANNetworkFlowProvider(final Node node, final OvsdbTerminationPointAugmentation port,
final NeutronNetwork network, final NeutronPort neutronPort, final Boolean isWrite) {
if (neutronPort != null && neutronPort.getDeviceOwner().equalsIgnoreCase(Constants.OWNER_ROUTER_GATEWAY) &&
LOG.debug("BridgeDelete: Delete bridge from config data store : {}"
+"Node : {}", bridge, node);
nodeCacheManager.nodeRemoved(node);
- // TODO SB_MIGRATION
- // Not sure if we want to do this yet
- southbound.deleteBridge(node);
- }
+ // Currently we only do not remove the integration bridge from configDS, which resolves
+ // bug 7461 where upon a rapid connection flap, the integration bridge is sometimes
+ // removed from the device due to ODL asynchronous processing of the connection flap.
+ if (bridge.getBridgeName() != null &&
+ !bridge.getBridgeName().getValue().equals(configurationService.getIntegrationBridgeName())) {
+ southbound.deleteBridge(node);
+ }
+ }
@Override
public void setDependencies(ServiceReference serviceReference) {
configurationService =
ovsdbInventoryService =
(OvsdbInventoryService) ServiceHelper.getGlobalInstance(OvsdbInventoryService.class, this);
ovsdbInventoryService.listenerAdded(this);
- vlanProvider =
+ vlanProvider =
(VLANProvider) ServiceHelper.getGlobalInstance(VLANProvider.class, this);
+ l2ForwardingProvider =
+ (L2ForwardingProvider) ServiceHelper.getGlobalInstance(L2ForwardingProvider.class, this);
}
@Override
public void setDependencies(Object impl) {
+ if (impl instanceof INeutronNetworkCRUD) {
+ neutronNetworkCache = (INeutronNetworkCRUD)impl;
+ } else if (impl instanceof L2ForwardingProvider) {
+ l2ForwardingProvider = (L2ForwardingProvider)impl;
+ }
}
}