/*
- * Copyright (c) 2015 Cisco Systems, Inc. and others. All rights reserved.
+ * Copyright (c) 2015 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,
package org.opendaylight.groupbasedpolicy.neutron.ovsdb;
import static com.google.common.base.Preconditions.checkNotNull;
+import static org.opendaylight.groupbasedpolicy.neutron.ovsdb.util.EndpointHelper.lookupEndpoint;
+import static org.opendaylight.groupbasedpolicy.neutron.ovsdb.util.EndpointHelper.updateEndpointRemoveLocation;
+import static org.opendaylight.groupbasedpolicy.neutron.ovsdb.util.EndpointHelper.updateEndpointWithLocation;
+import static org.opendaylight.groupbasedpolicy.neutron.ovsdb.util.InventoryHelper.checkOfOverlayConfig;
+import static org.opendaylight.groupbasedpolicy.neutron.ovsdb.util.InventoryHelper.getInventoryNodeConnectorIdString;
+import static org.opendaylight.groupbasedpolicy.neutron.ovsdb.util.InventoryHelper.getInventoryNodeIdString;
+import static org.opendaylight.groupbasedpolicy.neutron.ovsdb.util.InventoryHelper.removeTunnelsOfOverlayConfig;
+import static org.opendaylight.groupbasedpolicy.neutron.ovsdb.util.InventoryHelper.updateOfOverlayConfig;
+import static org.opendaylight.groupbasedpolicy.neutron.ovsdb.util.NeutronHelper.getEpKeyFromNeutronMapper;
+import static org.opendaylight.groupbasedpolicy.neutron.ovsdb.util.OvsdbHelper.createTunnelPort;
+import static org.opendaylight.groupbasedpolicy.neutron.ovsdb.util.OvsdbHelper.getManagerNode;
+import static org.opendaylight.groupbasedpolicy.neutron.ovsdb.util.OvsdbHelper.getOvsdbBridgeFromTerminationPoint;
+import static org.opendaylight.groupbasedpolicy.neutron.ovsdb.util.OvsdbHelper.getTopologyNode;
import java.util.ArrayList;
+import java.util.Collection;
import java.util.Collections;
+import java.util.HashMap;
import java.util.List;
-import java.util.Map.Entry;
+import java.util.Map;
import org.opendaylight.controller.md.sal.binding.api.DataBroker;
-import org.opendaylight.controller.md.sal.binding.api.DataChangeListener;
-import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker.DataChangeScope;
-import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeEvent;
+import org.opendaylight.controller.md.sal.binding.api.DataObjectModification;
+import org.opendaylight.controller.md.sal.binding.api.DataTreeChangeListener;
+import org.opendaylight.controller.md.sal.binding.api.DataTreeIdentifier;
+import org.opendaylight.controller.md.sal.binding.api.DataTreeModification;
+import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction;
+import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction;
import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
import org.opendaylight.ovsdb.southbound.SouthboundConstants;
-import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IpAddress;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.Uuid;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.UniqueId;
import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.EndpointService;
import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.endpoints.Endpoint;
import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.endpoints.EndpointKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
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.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.concepts.ListenerRegistration;
-import org.opendaylight.yangtools.yang.binding.DataObject;
import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import static org.opendaylight.groupbasedpolicy.neutron.ovsdb.util.OvsdbHelper.getManagerNode;
-import static org.opendaylight.groupbasedpolicy.neutron.ovsdb.util.OvsdbHelper.getTopologyNode;
-import static org.opendaylight.groupbasedpolicy.neutron.ovsdb.util.OvsdbHelper.createTunnelPort;
-import static org.opendaylight.groupbasedpolicy.neutron.ovsdb.util.OvsdbHelper.getOvsdbBridgeFromTerminationPoint;
-import static org.opendaylight.groupbasedpolicy.neutron.ovsdb.util.EndpointHelper.lookupEndpoint;
-import static org.opendaylight.groupbasedpolicy.neutron.ovsdb.util.EndpointHelper.updateEndpointWithLocation;
-import static org.opendaylight.groupbasedpolicy.neutron.ovsdb.util.NeutronHelper.getEpKeyFromNeutronMapper;
-import static org.opendaylight.groupbasedpolicy.neutron.ovsdb.util.InventoryHelper.checkOfOverlayConfig;
-import static org.opendaylight.groupbasedpolicy.neutron.ovsdb.util.InventoryHelper.getInventoryNodeIdString;
-import static org.opendaylight.groupbasedpolicy.neutron.ovsdb.util.InventoryHelper.getInventoryNodeConnectorIdString;
-import static org.opendaylight.groupbasedpolicy.neutron.ovsdb.util.InventoryHelper.updateOfOverlayConfig;
-
-public class TerminationPointDataChangeListener implements DataChangeListener, AutoCloseable {
+public class TerminationPointDataChangeListener implements DataTreeChangeListener<OvsdbTerminationPointAugmentation>,
+ AutoCloseable {
private static final String NEUTRON_EXTERNAL_ID_KEY = "iface-id";
- private final ListenerRegistration<DataChangeListener> registration;
+ private final ListenerRegistration<?> registration;
private final DataBroker dataBroker;
private final EndpointService epService;
private static final Logger LOG = LoggerFactory.getLogger(TerminationPointDataChangeListener.class);
public TerminationPointDataChangeListener(DataBroker dataBroker, EndpointService epService) {
this.dataBroker = checkNotNull(dataBroker);
this.epService = checkNotNull(epService);
- InstanceIdentifier<OvsdbTerminationPointAugmentation> iid = InstanceIdentifier
- .create(NetworkTopology.class)
- .child(Topology.class, new TopologyKey(SouthboundConstants.OVSDB_TOPOLOGY_ID))
- .child(Node.class)
- .child(TerminationPoint.class)
- .augmentation(OvsdbTerminationPointAugmentation.class);
- registration = dataBroker.registerDataChangeListener(LogicalDatastoreType.OPERATIONAL, iid, this, DataChangeScope.ONE);
+ InstanceIdentifier<OvsdbTerminationPointAugmentation> iid = InstanceIdentifier.create(NetworkTopology.class)
+ .child(Topology.class, new TopologyKey(SouthboundConstants.OVSDB_TOPOLOGY_ID))
+ .child(Node.class)
+ .child(TerminationPoint.class)
+ .augmentation(OvsdbTerminationPointAugmentation.class);
+ registration = dataBroker.registerDataTreeChangeListener(new DataTreeIdentifier<>(
+ LogicalDatastoreType.OPERATIONAL, iid), this);
requiredTunnelTypes = createSupportedTunnelsList();
}
private List<AbstractTunnelType> createSupportedTunnelsList() {
- List<AbstractTunnelType> required = new ArrayList<AbstractTunnelType>();
-// required.add(new VxlanGpeTunnelType());
+ List<AbstractTunnelType> required = new ArrayList<>();
required.add(new VxlanTunnelType());
+ required.add(new VxlanGpeTunnelType());
return Collections.unmodifiableList(required);
}
registration.close();
}
- @Override
- public void onDataChanged(AsyncDataChangeEvent<InstanceIdentifier<?>, DataObject> change) {
-
- /*
- * TerminationPoint notifications with OVSDB augmentations
- * vSwitch ports. Iterate through the list of new ports.
- */
- for (Entry<InstanceIdentifier<?>, DataObject> entry: change.getCreatedData().entrySet()) {
- if(entry.getValue() instanceof OvsdbTerminationPointAugmentation) {
- OvsdbTerminationPointAugmentation ovsdbTp = (OvsdbTerminationPointAugmentation)entry.getValue();
- InstanceIdentifier<OvsdbTerminationPointAugmentation> ovsdbTpIid =
- (InstanceIdentifier<OvsdbTerminationPointAugmentation>) entry.getKey();
- OvsdbBridgeAugmentation ovsdbBridge = getOvsdbBridgeFromTerminationPoint(ovsdbTpIid, dataBroker);
- processOvsdbBridge(ovsdbBridge, ovsdbTp,ovsdbTpIid);
- }
- }
-
- /*
- * Updates
- */
- for (Entry<InstanceIdentifier<?>, DataObject> entry: change.getUpdatedData().entrySet()) {
- if(entry.getValue() instanceof OvsdbTerminationPointAugmentation) {
- OvsdbTerminationPointAugmentation ovsdbTp = (OvsdbTerminationPointAugmentation)entry.getValue();
- InstanceIdentifier<OvsdbTerminationPointAugmentation> ovsdbTpIid =
- (InstanceIdentifier<OvsdbTerminationPointAugmentation>) entry.getKey();
- OvsdbBridgeAugmentation ovsdbBridge = getOvsdbBridgeFromTerminationPoint(ovsdbTpIid, dataBroker);
- processOvsdbBridge(ovsdbBridge, ovsdbTp,ovsdbTpIid);
- }
- }
+ /*
+ * When vSwitch is deleted, we loose data in operational DS to determine Iid of
+ * corresponding NodeId.
+ */
+ private static final Map<InstanceIdentifier<OvsdbTerminationPointAugmentation>, NodeId> NODE_ID_BY_TERMIN_POINT =
+ new HashMap<>();
- /*
- * Deletions
- */
- for (InstanceIdentifier<?> iid: change.getRemovedPaths()) {
- if (iid instanceof OvsdbTerminationPointAugmentation) {
- /*
- * Remove the state from OfOverlay?
- */
+ @Override
+ public void onDataTreeChanged(Collection<DataTreeModification<OvsdbTerminationPointAugmentation>> changes) {
+ for (DataTreeModification<OvsdbTerminationPointAugmentation> change: changes) {
+ DataObjectModification<OvsdbTerminationPointAugmentation> rootNode = change.getRootNode();
+ InstanceIdentifier<OvsdbTerminationPointAugmentation> ovsdbTpIid = change.getRootPath().getRootIdentifier();
+ OvsdbTerminationPointAugmentation origOvsdbTp = rootNode.getDataBefore();
+ switch (rootNode.getModificationType()) {
+ case SUBTREE_MODIFIED:
+ case WRITE:
+ OvsdbTerminationPointAugmentation updatedOvsdbTp = rootNode.getDataAfter();
+ OvsdbBridgeAugmentation ovsdbBridge = getOvsdbBridgeFromTerminationPoint(ovsdbTpIid, dataBroker);
+ if (origOvsdbTp == null) {
+ NODE_ID_BY_TERMIN_POINT.put(ovsdbTpIid,
+ new NodeId(getInventoryNodeIdString(ovsdbBridge, ovsdbTpIid, dataBroker)));
+ }
+
+ processOvsdbBridge(ovsdbBridge, updatedOvsdbTp, ovsdbTpIid);
+ break;
+ case DELETE:
+ processRemovedTp(NODE_ID_BY_TERMIN_POINT.get(ovsdbTpIid), origOvsdbTp, ovsdbTpIid);
+ break;
+ default:
+ break;
}
}
}
- private void processOvsdbBridge(OvsdbBridgeAugmentation ovsdbBridge, OvsdbTerminationPointAugmentation ovsdbTp, InstanceIdentifier<OvsdbTerminationPointAugmentation> ovsdbTpIid ) {
+ private void processOvsdbBridge(OvsdbBridgeAugmentation ovsdbBridge, OvsdbTerminationPointAugmentation ovsdbTp,
+ InstanceIdentifier<OvsdbTerminationPointAugmentation> ovsdbTpIid) {
checkNotNull(ovsdbBridge);
- if(ovsdbBridge.getBridgeName().getValue().equals(ovsdbTp.getName())) {
- LOG.debug("Termination Point {} same as Bridge {}. Not processing",ovsdbTp.getName(),ovsdbBridge.getBridgeName().getValue());
+ if (ovsdbBridge.getBridgeName().getValue().equals(ovsdbTp.getName())) {
+ LOG.debug("Termination Point {} same as Bridge {}. Not processing", ovsdbTp.getName(),
+ ovsdbBridge.getBridgeName().getValue());
return;
}
return;
}
+ InstanceIdentifier<Node> nodeIid = ovsdbTpIid.firstIdentifierOf(Node.class);
+ String externalId = getNeutronPortUuid(ovsdbTp);
+ Endpoint ep = null;
+ IpAddress hostIp = getIpFromOvsdb(ovsdbBridge);
+
/*
* Ports created by Nova have an external_id field
* in them, which is the Neutron port UUID. If a port
* (NodeId and NodeConnectorId from the inventory model)
* and the port name, constructed using the port UUID.
*/
- String externalId = getNeutronPortUuid(ovsdbTp);
- Endpoint ep = null;
+
if (externalId != null) {
- EndpointKey epKey = getEpKeyFromNeutronMapper(new Uuid(externalId), dataBroker);
+ EndpointKey epKey = getEpKeyFromNeutronMapper(new UniqueId(externalId), dataBroker);
if (epKey == null) {
- LOG.debug("TerminationPoint {} with external ID {} is not in Neutron Map", ovsdbTp,externalId);
+ LOG.debug("TerminationPoint {} with external ID {} is not in Neutron Map", ovsdbTp, externalId);
return;
}
- ep = lookupEndpoint(epKey, dataBroker);
+ ReadOnlyTransaction transaction = dataBroker.newReadOnlyTransaction();
+ ep = lookupEndpoint(epKey, transaction);
if (ep == null) {
- LOG.warn("TerminationPoint {} with external ID {} is in Neutron Map, but corresponding Endpoint {} isn't in Endpoint Repository", ovsdbTp,externalId,epKey);
+ LOG.warn("TerminationPoint {} with external ID {} is in Neutron Map, "
+ + "but corresponding Endpoint {} isn't in Endpoint Repository", ovsdbTp, externalId, epKey);
return;
}
/*
* OfOverlay augmentation. If it hasn't, go see if the
* tunnel ports exist, and if not, go and create them.
*/
- if (checkOfOverlayConfig(nodeIdString, requiredTunnelTypes, dataBroker) != true) {
-
- InstanceIdentifier<Node> nodeIid = ovsdbTpIid.firstIdentifierOf(Node.class);
+ if (!checkOfOverlayConfig(nodeIdString, requiredTunnelTypes, dataBroker)) {
checkNotNull(nodeIid);
-
/*
* Check to see if we need to create a
* tunnel port on the parent node
createTunnelPorts(nodeIid, dataBroker);
}
} else {
- LOG.debug("TerminationPoint {} has no external ID, not processing.",ovsdbTp);
+ LOG.debug("TerminationPoint {} had no external ID, not processing for external ID.", ovsdbTp);
+
}
- IpAddress hostIp = getIpFromOvsdb(ovsdbBridge);
+
/*
* This may be a notification for a tunnel we just created.
* In that case, we need to update the Inventory Node's OfOverlay
* augmentation with missing information
*/
+ AbstractTunnelType tunnel = getTunnelType(ovsdbTp, requiredTunnelTypes);
+ if (tunnel != null) {
+ updateOfOverlayConfig(hostIp, nodeIdString, nodeConnectorIdString, tunnel, dataBroker);
+ }
+ if (externalId != null) {
+ ReadWriteTransaction rwTx = dataBroker.newReadWriteTransaction();
+ updateEndpointWithLocation(ep, nodeIdString, nodeConnectorIdString, rwTx);
+ }
+ }
+
+ /**
+ * If removed termination point was a tunnel port,
+ * removes attached tunnels (namely Vxlan-type) from OVSDB bridge,
+ * else removes location info from TP.
+ *
+ * @param nodeId {@link NodeId}
+ * @param ovsdbTp {@link OvsdbTerminationPointAugmentation}
+ * @param ovsdbTpIid termination point's IID {@link InstanceIdentifier}
+ */
+ private void processRemovedTp(NodeId nodeId, OvsdbTerminationPointAugmentation ovsdbTp,
+ InstanceIdentifier<OvsdbTerminationPointAugmentation> ovsdbTpIid) {
if (isTunnelPort(ovsdbTp, requiredTunnelTypes)) {
- updateOfOverlayConfig(hostIp, nodeIdString, nodeConnectorIdString, requiredTunnelTypes, dataBroker);
+ removeTunnelsOfOverlayConfig(nodeId.getValue(), requiredTunnelTypes, dataBroker);
+ } else {
+ deleteLocationForTp(ovsdbTp);
}
+ }
+
+ /**
+ * Delete location on EP for given TP.
+ *
+ * @param ovsdbTp {@link OvsdbTerminationPointAugmentation}
+ */
+ private void deleteLocationForTp(OvsdbTerminationPointAugmentation ovsdbTp) {
+ String externalId = getNeutronPortUuid(ovsdbTp);
if (externalId != null) {
- updateEndpointWithLocation(ep, nodeIdString, nodeConnectorIdString, ovsdbTp.getName(), epService);
+ EndpointKey epKey = getEpKeyFromNeutronMapper(new UniqueId(externalId), dataBroker);
+ if (epKey == null) {
+ LOG.debug("TerminationPoint {} with external ID {} is not in Neutron Map.", ovsdbTp, externalId);
+ return;
+ }
+ ReadOnlyTransaction readOnlyTransaction = dataBroker.newReadOnlyTransaction();
+ Endpoint ep = lookupEndpoint(epKey, readOnlyTransaction);
+ readOnlyTransaction.close();
+ if (ep == null) {
+ LOG.warn("TerminationPoint {} with external ID {} is in Neutron Map,"
+ + " but corresponding Endpoint {} isn't in Endpoint Repository.", ovsdbTp, externalId, epKey);
+ return;
+ }
+ updateEndpointRemoveLocation(ep, dataBroker.newReadWriteTransaction());
+ } else {
+ LOG.debug("TerminationPoint {} has no external ID, not processing.", ovsdbTp);
}
}
/**
+ * Check to see if the {@link OvsdbTerminationPointAugmentation} is also a Tunnel port that we
+ * care about.
+ *
+ * @param ovsdbTp {@link OvsdbTerminationPointAugmentation}
+ * @param requiredTunnelTypes {@link List} of tunnel types
+ */
+ private static AbstractTunnelType getTunnelType(OvsdbTerminationPointAugmentation ovsdbTp,
+ List<AbstractTunnelType> requiredTunnelTypes) {
+ if (ovsdbTp.getInterfaceType() != null) {
+ for (AbstractTunnelType tunnelType : requiredTunnelTypes) {
+ if (tunnelType.isValidTunnelPort(ovsdbTp)) {
+ return tunnelType;
+ }
+ }
+ }
+ return null;
+ }
+
+ /*
* Check to see if the {@link OvsdbTerminationPointAugmentation}
* is also a Tunnel port that we care about.
*
- * @param ovsdbTp
- * @param requiredTunnelTypes
+ * @param ovsdbTp {@link OvsdbTerminationPointAugmentation}
+ *
+ * @param requiredTunnelTypes {@link List} of tunnel types
+ *
* @return true if it's a required tunnel port, false if it isn't
*/
private boolean isTunnelPort(OvsdbTerminationPointAugmentation ovsdbTp,
- List<AbstractTunnelType> requiredTunnelTypes) {
+ List<AbstractTunnelType> requiredTunnelTypes) {
if (ovsdbTp.getInterfaceType() != null) {
- for (AbstractTunnelType tunnelType: requiredTunnelTypes) {
+ for (AbstractTunnelType tunnelType : requiredTunnelTypes) {
if (tunnelType.isValidTunnelPort(ovsdbTp)) {
return true;
}
return false;
}
-
/**
* Get the Neutron Port UUID from an {@link OvsdbTerminationPointAugmentation}.
* The Neutron Port UUID is stored as an "external-id" in the termination point.
*
- * @param ovsdbTp The OVSDB Termination Point augmentation
+ * @param ovsdbTp The {@link OvsdbTerminationPointAugmentation}
* @return The String representation of the Neutron Port UUID, null if not present
*/
private String getNeutronPortUuid(OvsdbTerminationPointAugmentation ovsdbTp) {
if (ovsdbTp.getInterfaceExternalIds() == null) {
return null;
}
- for (InterfaceExternalIds id: ovsdbTp.getInterfaceExternalIds()) {
- if (id.getExternalIdKey() != null
- && id.getExternalIdKey().equals(NEUTRON_EXTERNAL_ID_KEY)) {
+ for (InterfaceExternalIds id : ovsdbTp.getInterfaceExternalIds()) {
+ if (id.getExternalIdKey() != null && id.getExternalIdKey().equals(NEUTRON_EXTERNAL_ID_KEY)) {
if (id.getExternalIdValue() != null) {
return id.getExternalIdValue();
* Check to see if all tunnel ports are present, and if not,
* create them.
*
- * @param tpIid
- * @return
+ * @param nodeIid {@link InstanceIdentifier}
+ * @param dataBroker {@link DataBroker}
*/
private void createTunnelPorts(InstanceIdentifier<Node> nodeIid, DataBroker dataBroker) {
* See if this Topology Node has the required tunnel ports,
* and if not, go and create them
*/
- for (AbstractTunnelType tunnelType: requiredTunnelTypes) {
+ for (AbstractTunnelType tunnelType : requiredTunnelTypes) {
boolean tunnelPresent = false;
- for (TerminationPoint tp: node.getTerminationPoint()) {
- OvsdbTerminationPointAugmentation tpAug =
- tp.getAugmentation(OvsdbTerminationPointAugmentation.class);
+ for (TerminationPoint tp : node.getTerminationPoint()) {
+ OvsdbTerminationPointAugmentation tpAug = tp.getAugmentation(OvsdbTerminationPointAugmentation.class);
checkNotNull(tpAug);
if (tunnelType.isValidTunnelPort(tpAug)) {
tunnelPresent = true;
+ break;
}
}
- if (tunnelPresent == false) {
+ if (!tunnelPresent) {
createTunnelPort(nodeIid, node, tunnelType, dataBroker);
}
}
*/
OvsdbNodeAugmentation managerNode = getManagerNode(ovsdbBridge, dataBroker);
- if (managerNode == null) return null;
+ if (managerNode == null) {
+ return null;
+ }
if (managerNode.getConnectionInfo() != null) {
return managerNode.getConnectionInfo().getRemoteIp();
return null;
}
}
-