* Fixed incorrect data change scope for inventory change listeners.
* Fixed bug that ignored inter-swtich links affected by a removed
node were not removed.
* Enable integration tests again.
Change-Id: I4249cd34e985b85c0546b2381f60dd08ddfcad30
Signed-off-by: Shigeru Yasuda <s-yasuda@da.jp.nec.com>
package org.opendaylight.vtn.manager.internal.inventory;
-import java.util.List;
-
-import com.google.common.base.Optional;
-import com.google.common.util.concurrent.CheckedFuture;
-
-import org.slf4j.Logger;
-
-import org.opendaylight.vtn.manager.VTNException;
-
-import org.opendaylight.vtn.manager.internal.TxContext;
import org.opendaylight.vtn.manager.internal.TxQueue;
import org.opendaylight.vtn.manager.internal.TxTask;
import org.opendaylight.vtn.manager.internal.util.DataStoreListener;
-import org.opendaylight.vtn.manager.internal.util.DataStoreUtils;
-import org.opendaylight.vtn.manager.internal.util.inventory.InventoryReader;
-import org.opendaylight.vtn.manager.internal.util.inventory.InventoryUtils;
-import org.opendaylight.vtn.manager.internal.util.inventory.SalNode;
-import org.opendaylight.vtn.manager.internal.util.inventory.SalPort;
import org.opendaylight.controller.md.sal.binding.api.DataBroker;
-import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction;
import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker.DataChangeScope;
import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
-import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException;
import org.opendaylight.yangtools.yang.binding.DataObject;
-import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
-
-import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.impl.inventory.rev150209.vtn.node.info.VtnPort;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.impl.inventory.rev150209.vtn.port.info.PortLink;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.impl.topology.rev150209.IgnoredLinks;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.impl.topology.rev150209.VtnTopology;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.impl.topology.rev150209.ignored.links.IgnoredLink;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.impl.topology.rev150209.vtn.topology.VtnLink;
-
-import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId;
-
-import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.LinkId;
/**
* Base class for MD-SAL data change listeners that maintain the VTN inventory
protected final void submitInitial(TxTask<?> task) {
txQueue.postFirst(task);
}
-
- /**
- * Read the specified VTN port asynchronously.
- *
- * @param tx A {@link ReadWriteTransaction} instance.
- * @param sport A {@link SalPort} instance corresponding to the VTN port.
- * @return A future associated with a MD-SAL datastore read transaction.
- */
- protected final CheckedFuture<Optional<VtnPort>, ReadFailedException> read(
- ReadWriteTransaction tx, SalPort sport) {
- InstanceIdentifier<VtnPort> path = sport.getVtnPortIdentifier();
- return tx.read(LogicalDatastoreType.OPERATIONAL, path);
- }
-
- /**
- * Determine whether the given VTN port is present or not.
- *
- * @param tx A {@link ReadWriteTransaction} instance.
- * @param sport A {@link SalPort} instance corresponding to the VTN port.
- * @return {@code true} only if the specified VTN port is present.
- * @throws VTNException
- * An error occurred.
- */
- protected final boolean isPresent(ReadWriteTransaction tx, SalPort sport)
- throws VTNException {
- InstanceIdentifier<VtnPort> path = sport.getVtnPortIdentifier();
- LogicalDatastoreType oper = LogicalDatastoreType.OPERATIONAL;
- return DataStoreUtils.read(tx, oper, path).isPresent();
- }
-
- /**
- * Add the given inter-switch link information into the VTN inventory data.
- *
- * @param tx A {@link ReadWriteTransaction} instance.
- * @param lid The identifier of the created link.
- * @param src A {@link SalPort} instance corresponding to the source
- * of the created link.
- * @param dst A {@link SalPort} instance corresponding to the destination
- * of the created link.
- * @return {@code true} if the link was added to the vtn-topology list.
- * {@code false} if the link was added to the ignored-links list.
- * @throws VTNException
- * An error occurred.
- */
- protected final boolean addVtnLink(ReadWriteTransaction tx, LinkId lid,
- SalPort src, SalPort dst)
- throws VTNException {
- // Determine whether the VTN port for both termination points are
- // present or not.
- CheckedFuture<Optional<VtnPort>, ReadFailedException> sf =
- read(tx, src);
- CheckedFuture<Optional<VtnPort>, ReadFailedException> df =
- read(tx, dst);
- boolean srcPresent = DataStoreUtils.read(sf).isPresent();
- boolean dstPresent = DataStoreUtils.read(df).isPresent();
-
- boolean ret;
- if (srcPresent && dstPresent) {
- // Create link information.
- createVtnLink(tx, lid, src, dst);
- ret = true;
- } else {
- // Put link information into ignored link list.
- InstanceIdentifier<IgnoredLink> key =
- InventoryUtils.toIgnoredLinkIdentifier(lid);
- IgnoredLink ilink =
- InventoryUtils.toIgnoredLinkBuilder(lid, src, dst).build();
- tx.merge(LogicalDatastoreType.OPERATIONAL, key, ilink, true);
- ret = false;
- }
-
- return ret;
- }
-
- /**
- * Remove all VTN links affected by the the removed VTN node.
- *
- * @param tx A {@link ReadWriteTransaction} instance.
- * @param snode A {@link SalNode} instance corresponding to the removed
- * VTN node.
- * @throws VTNException
- * An error occurred.
- */
- protected final void removeVtnLink(ReadWriteTransaction tx, SalNode snode)
- throws VTNException {
- removeVtnTopologyLink(tx, snode);
- removeIgnoredLink(tx, snode);
- }
-
- /**
- * Remove all VTN links in vtn-topology affected by the removed VTN node.
- *
- * @param tx A {@link ReadWriteTransaction} instance.
- * @param snode A {@link SalNode} instance corresponding to the removed
- * VTN node.
- * @throws VTNException
- * An error occurred.
- */
- protected final void removeVtnTopologyLink(ReadWriteTransaction tx,
- SalNode snode)
- throws VTNException {
- InstanceIdentifier<VtnTopology> topoPath =
- InstanceIdentifier.create(VtnTopology.class);
- LogicalDatastoreType oper = LogicalDatastoreType.OPERATIONAL;
- VtnTopology topology = DataStoreUtils.read(tx, oper, topoPath).
- orNull();
- if (topology == null) {
- return;
- }
-
- List<VtnLink> links = topology.getVtnLink();
- if (links == null) {
- return;
- }
-
- long dpid = snode.getNodeNumber();
- for (VtnLink vlink: links) {
- LinkId lid = vlink.getLinkId();
- SalPort src = SalPort.create(vlink.getSource());
- SalPort dst = SalPort.create(vlink.getDestination());
- long srcDpid = src.getNodeNumber();
- long dstDpid = dst.getNodeNumber();
-
- boolean rmLink = false;
- if (srcDpid == dpid) {
- rmLink = true;
- if (dstDpid != dpid) {
- removePortLink(tx, dst, lid);
- }
- } else if (dstDpid == dpid) {
- rmLink = true;
- removePortLink(tx, src, lid);
- }
-
- if (rmLink) {
- InstanceIdentifier<VtnLink> lpath =
- InventoryUtils.toVtnLinkIdentifier(lid);
- tx.delete(oper, lpath);
- }
- }
- }
-
- /**
- * Remove all VTN links in ignored-links affected by the removed VTN node.
- *
- * @param tx A {@link ReadWriteTransaction} instance.
- * @param snode A {@link SalNode} instance corresponding to the removed
- * VTN node.
- * @throws VTNException
- * An error occurred.
- */
- protected final void removeIgnoredLink(ReadWriteTransaction tx,
- SalNode snode)
- throws VTNException {
- InstanceIdentifier<IgnoredLinks> igPath =
- InstanceIdentifier.create(IgnoredLinks.class);
- LogicalDatastoreType oper = LogicalDatastoreType.OPERATIONAL;
- IgnoredLinks igList = DataStoreUtils.read(tx, oper, igPath).orNull();
- if (igList == null) {
- return;
- }
-
- List<IgnoredLink> links = igList.getIgnoredLink();
- if (links == null) {
- return;
- }
-
- long dpid = snode.getNodeNumber();
- for (IgnoredLink vlink: links) {
- LinkId lid = vlink.getLinkId();
- SalPort src = SalPort.create(vlink.getSource());
- SalPort dst = SalPort.create(vlink.getDestination());
- long srcDpid = src.getNodeNumber();
- long dstDpid = dst.getNodeNumber();
-
- if (srcDpid == dpid || dstDpid == dpid) {
- InstanceIdentifier<VtnLink> lpath =
- InventoryUtils.toVtnLinkIdentifier(lid);
- tx.delete(LogicalDatastoreType.OPERATIONAL, lpath);
- }
- }
- }
-
- /**
- * Remove all VTN links affected by the removed VTN port.
- *
- * @param tx A {@link ReadWriteTransaction} instance.
- * @param vport A {@link VtnPort} instance corresponding to the removed
- * VTN port.
- */
- protected final void removeVtnLink(ReadWriteTransaction tx,
- VtnPort vport) {
- List<PortLink> links = vport.getPortLink();
- if (links == null) {
- return;
- }
-
- for (PortLink plink: links) {
- LinkId lid = plink.getLinkId();
- NodeConnectorId peer = plink.getPeer();
- SalPort p = SalPort.create(peer);
- removePortLink(tx, p, lid);
-
- InstanceIdentifier<VtnLink> lpath =
- InventoryUtils.toVtnLinkIdentifier(lid);
- tx.delete(LogicalDatastoreType.OPERATIONAL, lpath);
- }
- }
-
- /**
- * Remove the specified port link.
- *
- * @param tx A {@link ReadWriteTransaction} instance.
- * @param sport A {@link SalPort} instance corresponding to a VTN port.
- * @param lid A {@link LinkId} that specifies inter-switch link to be
- * removed.
- */
- protected final void removePortLink(ReadWriteTransaction tx, SalPort sport,
- LinkId lid) {
- InstanceIdentifier<PortLink> path = sport.getPortLinkIdentifier(lid);
- tx.delete(LogicalDatastoreType.OPERATIONAL, path);
- }
-
- /**
- * Try to resolve ignored inter-switch links.
- *
- * @param ctx A runtime context for transaction task.
- * @param logger A {@link Logger} instance.
- * @throws VTNException
- * An error occurred.
- */
- protected final void resolveIgnoredLinks(TxContext ctx, Logger logger)
- throws VTNException {
- // Read all ignored inter-switch links.
- InstanceIdentifier<IgnoredLinks> igPath =
- InstanceIdentifier.create(IgnoredLinks.class);
- ReadWriteTransaction tx = ctx.getReadWriteTransaction();
- LogicalDatastoreType oper = LogicalDatastoreType.OPERATIONAL;
- IgnoredLinks igLinks = DataStoreUtils.read(tx, oper, igPath).orNull();
- if (igLinks == null) {
- return;
- }
-
- List<IgnoredLink> igList = igLinks.getIgnoredLink();
- if (igList == null) {
- return;
- }
-
- InventoryReader reader = ctx.getInventoryReader();
- for (IgnoredLink ignored: igList) {
- SalPort src = SalPort.create(ignored.getSource());
- SalPort dst = SalPort.create(ignored.getDestination());
- if (reader.get(src) != null && reader.get(dst) != null) {
- // Move this link to vtn-topology.
- LinkId lid = ignored.getLinkId();
- InstanceIdentifier<IgnoredLink> ipath =
- InventoryUtils.toIgnoredLinkIdentifier(lid);
- tx.delete(oper, ipath);
- createVtnLink(tx, lid, src, dst);
- logger.info("Inter-switch link has been resolved: {}: {} -> {}",
- lid.getValue(), src, dst);
- }
- }
- }
-
- /**
- * Create a VTN link information.
- *
- * @param tx A {@link ReadWriteTransaction} instance.
- * @param lid The identifier of the created link.
- * @param src A {@link SalPort} instance corresponding to the source
- * of the created link.
- * @param dst A {@link SalPort} instance corresponding to the destination
- * of the created link.
- */
- private void createVtnLink(ReadWriteTransaction tx, LinkId lid,
- SalPort src, SalPort dst) {
- // Put the link information into vtn-topology list.
- InstanceIdentifier<VtnLink> key =
- InventoryUtils.toVtnLinkIdentifier(lid);
- VtnLink vlink = InventoryUtils.toVtnLinkBuilder(lid, src, dst).build();
- LogicalDatastoreType oper = LogicalDatastoreType.OPERATIONAL;
- tx.merge(oper, key, vlink, true);
-
- // Create source port link.
- InstanceIdentifier<PortLink> pkey = src.getPortLinkIdentifier(lid);
- PortLink plink = InventoryUtils.toPortLinkBuilder(lid, dst).build();
- tx.merge(oper, pkey, plink, true);
-
- // Create destination port link.
- pkey = dst.getPortLinkIdentifier(lid);
- plink = InventoryUtils.toPortLinkBuilder(lid, src).build();
- tx.merge(oper, pkey, plink, true);
- }
}
--- /dev/null
+/*
+ * Copyright (c) 2015 NEC Corporation
+ * 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.vtn.manager.internal.inventory;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import com.google.common.base.Optional;
+
+import org.slf4j.Logger;
+
+import org.opendaylight.vtn.manager.VTNException;
+
+import org.opendaylight.vtn.manager.internal.TxContext;
+import org.opendaylight.vtn.manager.internal.util.DataStoreUtils;
+import org.opendaylight.vtn.manager.internal.util.tx.AbstractTxTask;
+
+import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+/**
+ * Base class for tasks to update VTN inventory information.
+ *
+ * @param <T> The type of MD-SAL inventory to listen.
+ * @param <L> The type of instance which represents the location of the
+ * target inventory.
+ */
+abstract class InventoryUpdateTask<T extends DataObject, L>
+ extends AbstractTxTask<Void> {
+ /**
+ * A map that keeps locations of notified inventories.
+ */
+ private final Map<L, InstanceIdentifier<T>> updated = new HashMap<>();
+
+ /**
+ * A logger instance.
+ */
+ private final Logger logger;
+
+ /**
+ * Construct a new instance.
+ *
+ * @param log A {@link Logger} instance.
+ */
+ InventoryUpdateTask(Logger log) {
+ logger = log;
+ }
+
+ /**
+ * Add an inventory information notified by a data change event.
+ *
+ * @param path Path to the target instance.
+ * @param loc An object that represents the location of the target
+ * inventory.
+ */
+ final void addUpdated(InstanceIdentifier<T> path, L loc) {
+ updated.put(loc, path);
+ }
+
+ /**
+ * Determine whether this task contains at least one notification or not.
+ *
+ * @return {@code true} only if this instance contains at least one
+ * notification.
+ */
+ final boolean hasUpdates() {
+ return !updated.isEmpty();
+ }
+
+ /**
+ * Return a {@link Logger} instance.
+ *
+ * @return A {@link Logger} instance.
+ */
+ final Logger getLogger() {
+ return logger;
+ }
+
+ /**
+ * Add an inventory information notified by a data change event.
+ *
+ * @param ctx A {@link TxContext} instance.
+ * @param tx A {@link ReadWriteTransaction} instance.
+ * @param loc An object that represents the location of the target
+ * inventory.
+ * @param path Path to the target inventory in the MD-SAL datastore.
+ * @param data An inventory data in the MD-SAL datastore.
+ * @throws VTNException An error occurred.
+ */
+ protected abstract void add(TxContext ctx, ReadWriteTransaction tx,
+ L loc, InstanceIdentifier<T> path, T data)
+ throws VTNException;
+
+ /**
+ * Remove an inventory information notified by a data change event.
+ *
+ * @param ctx A {@link TxContext} instance.
+ * @param tx A {@link ReadWriteTransaction} instance.
+ * @param loc An object that represents the location of the target
+ * inventory.
+ * @throws VTNException An error occurred.
+ */
+ protected abstract void remove(TxContext ctx, ReadWriteTransaction tx,
+ L loc)
+ throws VTNException;
+
+ /**
+ * A post-event hook which will be invoked after event processing.
+ *
+ * @param ctx A {@link TxContext} instance.
+ * @param added {@code true} is passed if at least one inventory
+ * information has been created.
+ * @throws VTNException An error occurred.
+ */
+ protected abstract void fixUp(TxContext ctx, boolean added)
+ throws VTNException;
+
+ // TxTask
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public final Void execute(TxContext ctx) throws VTNException {
+ ReadWriteTransaction tx = ctx.getReadWriteTransaction();
+ LogicalDatastoreType oper = LogicalDatastoreType.OPERATIONAL;
+ boolean added = false;
+ for (Map.Entry<L, InstanceIdentifier<T>> entry: updated.entrySet()) {
+ // Read the notified inventory.
+ L loc = entry.getKey();
+ InstanceIdentifier<T> path = entry.getValue();
+ Optional<T> opt = DataStoreUtils.read(tx, oper, path);
+ if (opt.isPresent()) {
+ // Add the inventory information corresponding to the target
+ // inventory.
+ add(ctx, tx, loc, path, opt.get());
+ added = true;
+ } else {
+ // Remove the inventory information corresponding to the target
+ // inventory.
+ remove(ctx, tx, loc);
+ }
+ }
+
+ fixUp(ctx, added);
+ return null;
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2015 NEC Corporation
+ * 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.vtn.manager.internal.inventory;
+
+import java.util.HashSet;
+import java.util.Set;
+
+import com.google.common.base.Optional;
+
+import org.slf4j.Logger;
+
+import org.opendaylight.vtn.manager.VTNException;
+
+import org.opendaylight.vtn.manager.internal.TxContext;
+import org.opendaylight.vtn.manager.internal.VTNManagerProvider;
+import org.opendaylight.vtn.manager.internal.util.DataStoreUtils;
+import org.opendaylight.vtn.manager.internal.util.inventory.InventoryReader;
+import org.opendaylight.vtn.manager.internal.util.inventory.InventoryUtils;
+import org.opendaylight.vtn.manager.internal.util.inventory.LinkEdge;
+import org.opendaylight.vtn.manager.internal.util.inventory.SalPort;
+import org.opendaylight.vtn.manager.internal.util.tx.AbstractTxTask;
+
+import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.impl.topology.rev150209.ignored.links.IgnoredLink;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.impl.topology.rev150209.vtn.topology.VtnLink;
+
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.LinkId;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Link;
+
+/**
+ * A MD-SAL datastore transaction task that updates VTN topology information.
+ */
+final class LinkUpdateTask extends AbstractTxTask<Void> {
+ /**
+ * A set of paths to updated inter-switch links.
+ */
+ private final Set<InstanceIdentifier<Link>> updated = new HashSet<>();
+
+ /**
+ * A logger instance.
+ */
+ private final Logger logger;
+
+ /**
+ * Construct a new instance.
+ *
+ * @param log A {@link Logger} instance.
+ */
+ LinkUpdateTask(Logger log) {
+ logger = log;
+ }
+
+ /**
+ * Add a link information notified by a data change event.
+ *
+ * @param path Path to the target link.
+ */
+ void addUpdated(InstanceIdentifier<Link> path) {
+ updated.add(path);
+ }
+
+ /**
+ * Determine whether this task contains at least one notification or not.
+ *
+ * @return {@code true} only if this instance contains at least one
+ * notification.
+ */
+ boolean hasUpdates() {
+ return !updated.isEmpty();
+ }
+
+ /**
+ * Add a VTN link information corresponding to the given MD-SAL
+ * inter-switch link.
+ *
+ * @param tx A {@link ReadWriteTransaction} instance.
+ * @param reader An {@link InventoryReader} instance.
+ * @param link A {@link Link} instance.
+ * @throws VTNException An error occurred.
+ */
+ private void add(ReadWriteTransaction tx, InventoryReader reader,
+ Link link) throws VTNException {
+ LinkEdge le;
+ try {
+ le = new LinkEdge(link);
+ } catch (RuntimeException e) {
+ logger.debug("Ignore unsupported inter-switch link: " + link, e);
+ return;
+ }
+
+ LinkId lid = link.getLinkId();
+ SalPort src = le.getSourcePort();
+ SalPort dst = le.getDestinationPort();
+ if (!InventoryUtils.addVtnLink(tx, reader, lid, src, dst)) {
+ logger.warn("Ignore inter-switch link: {}: {} -> {}",
+ lid.getValue(), src, dst);
+ }
+ }
+
+ /**
+ * Remove a VTN link information corresponding to the given MD-SAL
+ * inter-switch link.
+ *
+ * @param tx A {@link ReadWriteTransaction} instance.
+ * @param path Path to the removed inter-switch link.
+ * @throws VTNException An error occurred.
+ */
+ private void remove(ReadWriteTransaction tx, InstanceIdentifier<Link> path)
+ throws VTNException {
+ LinkId lid = InventoryUtils.getLinkId(path);
+ if (lid == null) {
+ logger.warn("Ignore invalid inter-switch link path: {}", path);
+ return;
+ }
+
+ // Read the VTN link information corresponding to the given link.
+ LogicalDatastoreType oper = LogicalDatastoreType.OPERATIONAL;
+ InstanceIdentifier<VtnLink> lpath =
+ InventoryUtils.toVtnLinkIdentifier(lid);
+ Optional<VtnLink> opt = DataStoreUtils.read(tx, oper, lpath);
+ if (opt.isPresent()) {
+ VtnLink vlink = opt.get();
+ SalPort src = SalPort.create(vlink.getSource());
+ SalPort dst = SalPort.create(vlink.getDestination());
+
+ // Remove the link from vtn-topology list.
+ tx.delete(oper, lpath);
+
+ // Remove port links.
+ InventoryUtils.removePortLink(tx, src, lid);
+ InventoryUtils.removePortLink(tx, dst, lid);
+ } else {
+ // Remove the link from ignored-links list.
+ InstanceIdentifier<IgnoredLink> ipath =
+ InventoryUtils.toIgnoredLinkIdentifier(lid);
+ DataStoreUtils.delete(tx, oper, ipath);
+ }
+ }
+
+ // TxTask
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public Void execute(TxContext ctx) throws VTNException {
+ ReadWriteTransaction tx = ctx.getReadWriteTransaction();
+ LogicalDatastoreType oper = LogicalDatastoreType.OPERATIONAL;
+ InventoryReader reader = ctx.getInventoryReader();
+ for (InstanceIdentifier<Link> path: updated) {
+ // Read the notified link.
+ Optional<Link> opt = DataStoreUtils.read(tx, oper, path);
+ if (opt.isPresent()) {
+ // Add the inter-switch link information.
+ add(tx, reader, opt.get());
+ } else {
+ // Remove the inter-swtich link information.
+ remove(tx, path);
+ }
+ }
+
+ return null;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void onFailure(VTNManagerProvider provider, Throwable t) {
+ logger.error("Failed to update VTN link information.", t);
+ }
+}
+++ /dev/null
-/*
- * Copyright (c) 2015 NEC Corporation
- * 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.vtn.manager.internal.inventory;
-
-import org.opendaylight.vtn.manager.internal.TxTask;
-
-import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
-
-import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnector;
-
-/**
- * An event context used to handle node connector events.
- */
-interface NodeConnectorEventContext extends TxTask<Void> {
- /**
- * Add the given node to the node map to be updated.
- *
- * @param path The identifier of the node connector to be added.
- * @param nc A {@link NodeConnector} instance to be added
- * @param label A label usd only for logging.
- */
- void addUpdated(InstanceIdentifier<NodeConnector> path, NodeConnector nc,
- String label);
-
- /**
- * Add the given node to the node map to be removed.
- *
- * @param path The identifier of the node connector to be added.
- * @param nc A {@link NodeConnector} instance to be added.
- */
- void addRemoved(InstanceIdentifier<NodeConnector> path, NodeConnector nc);
-
- /**
- * Determine whether this instance contains at least one port information
- * to be updated or removed.
- *
- * @return {@code true} only if this instance contains at least one port
- * information to be updated or removed.
- */
- boolean hasPort();
-}
package org.opendaylight.vtn.manager.internal.inventory;
-import java.util.HashMap;
-import java.util.Map;
import java.util.Set;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import org.opendaylight.vtn.manager.VTNException;
-
-import org.opendaylight.vtn.manager.internal.TxContext;
import org.opendaylight.vtn.manager.internal.TxQueue;
-import org.opendaylight.vtn.manager.internal.VTNManagerProvider;
-import org.opendaylight.vtn.manager.internal.util.DataStoreUtils;
-import org.opendaylight.vtn.manager.internal.util.inventory.InventoryReader;
+import org.opendaylight.vtn.manager.internal.util.MiscUtils;
import org.opendaylight.vtn.manager.internal.util.inventory.InventoryUtils;
-import org.opendaylight.vtn.manager.internal.util.inventory.SalNode;
import org.opendaylight.vtn.manager.internal.util.inventory.SalPort;
-import org.opendaylight.vtn.manager.internal.util.tx.AbstractTxTask;
import org.opendaylight.controller.md.sal.binding.api.DataBroker;
-import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction;
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.common.api.data.LogicalDatastoreType;
import org.opendaylight.yangtools.yang.binding.DataObject;
import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.impl.inventory.rev150209.VtnOpenflowVersion;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.impl.inventory.rev150209.vtn.node.info.VtnPort;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.impl.inventory.rev150209.vtn.nodes.VtnNode;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.impl.inventory.rev150209.vtn.nodes.VtnNodeBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.types.rev150209.VtnUpdateType;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNodeConnector;
import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId;
import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes;
import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnector;
* Listener class that listens the change of MD-SAL node connectors.
*/
public final class NodeConnectorListener
- extends InventoryMaintainer<NodeConnector, NodeConnectorEventContext> {
+ extends InventoryMaintainer<FlowCapableNodeConnector, PortUpdateTask> {
/**
* Logger instance.
*/
private static final Logger LOG =
LoggerFactory.getLogger(NodeConnectorListener.class);
- /**
- * MD-SAL transaction task that updates the VTN port.
- */
- private class PortUpdatedTask extends AbstractTxTask<Void>
- implements NodeConnectorEventContext {
- /**
- * A map that keeps created or updated MD-SAL node connectors.
- */
- private final Map<InstanceIdentifier<NodeConnector>, SalPort> updated =
- new HashMap<>();
-
- /**
- * A map that keeps removed MD-SAL node connectors.
- p*/
- private final Map<InstanceIdentifier<NodeConnector>, SalPort> removed =
- new HashMap<>();
-
- /**
- * Update the given node connector in the VTN inventory datastore.
- *
- * @param ctx A MD-SAL datastore transaction context.
- * @param tx A {@link ReadWriteTransaction} instance.
- * @param path Instance identifier of the updated MD-SAL node
- * connector.
- * @param sport A {@link SalPort} instance corresponding to the
- * updated MD-SAL node connector.
- * @throws VTNException An error occurred.
- */
- private void add(TxContext ctx, ReadWriteTransaction tx,
- InstanceIdentifier<NodeConnector> path,
- SalPort sport) throws VTNException {
- // Read MD-SAL node connector from the datastore.
- LogicalDatastoreType oper = LogicalDatastoreType.OPERATIONAL;
- NodeConnector nc = DataStoreUtils.read(tx, oper, path).orNull();
- if (nc == null) {
- LOG.debug("Ignore bogus event: {}", sport);
- return;
- }
-
- // Read VTN node from the datastore.
- SalNode snode = sport.getSalNode();
- InstanceIdentifier<VtnNode> vnpath = snode.getVtnNodeIdentifier();
- VtnNode vnode = DataStoreUtils.read(tx, oper, vnpath).orNull();
- if (vnode != null) {
- // Create or update a VTN port.
- VtnPort vport = InventoryUtils.toVtnPortBuilder(nc).build();
- tx.merge(oper, sport.getVtnPortIdentifier(), vport, true);
-
- if (vnode.getOpenflowVersion() == null) {
- // Estimate protocol version.
- VtnOpenflowVersion v =
- InventoryUtils.getOpenflowVersion(nc);
- VtnNode vn = new VtnNodeBuilder().setId(snode.getNodeId()).
- setOpenflowVersion(v).build();
- tx.merge(oper, vnpath, vn, true);
- }
-
- // Cache this port into the inventory reader.
- InventoryReader reader = ctx.getInventoryReader();
- reader.prefetch(snode, vnode);
- resolveIgnoredLinks(ctx, LOG);
- } else {
- LOG.debug("Ignore port because VTN node is not present: {}",
- sport);
- }
- }
-
- /**
- * Remove the given node connector from the VTN inventory datastore.
- *
- * @param tx A {@link ReadWriteTransaction} instance.
- * @param path Instance identifier of the updated MD-SAL node
- * connector.
- * @param sport A {@link SalPort} instance corresponding to the
- * updated MD-SAL node connector.
- * @throws VTNException An error occurred.
- */
- private void remove(ReadWriteTransaction tx,
- InstanceIdentifier<NodeConnector> path,
- SalPort sport) throws VTNException {
- LogicalDatastoreType oper = LogicalDatastoreType.OPERATIONAL;
- InstanceIdentifier<VtnPort> vpath = sport.getVtnPortIdentifier();
- VtnPort vport = DataStoreUtils.read(tx, oper, vpath).orNull();
- if (vport != null) {
- // Remove VTN links affected by the removed port.
- removeVtnLink(tx, vport);
-
- // Remove a VTN port.
- tx.delete(oper, vpath);
- }
- }
-
- /**
- * Convert the given MD-SAL node connector into a {@link SalPort}
- * instance.
- *
- * @param nc A {@link NodeConnector} instance.
- * @param label A label used only for logging.
- * @return A {@link SalPort} instance on success.
- * {@code null} on failure.
- */
- private SalPort toSalPort(NodeConnector nc, String label) {
- NodeConnectorId id = nc.getId();
- SalPort sport = SalPort.create(id);
-
- // Ignore notification on logical port completely.
- if (sport == null && LOG.isDebugEnabled() &&
- !SalPort.isLogicalPort(id)) {
- LOG.debug("{}: Ignore unsupported node connector: {}",
- label, id);
- }
- return sport;
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public Void execute(TxContext ctx) throws VTNException {
- // Process node connector deletion events.
- ReadWriteTransaction tx = ctx.getReadWriteTransaction();
- for (Map.Entry<InstanceIdentifier<NodeConnector>, SalPort> entry:
- removed.entrySet()) {
- InstanceIdentifier<NodeConnector> path = entry.getKey();
- SalPort sport = entry.getValue();
- remove(tx, path, sport);
- }
-
- // Process node connector update events.
- for (Map.Entry<InstanceIdentifier<NodeConnector>, SalPort> entry:
- updated.entrySet()) {
- InstanceIdentifier<NodeConnector> path = entry.getKey();
- SalPort sport = entry.getValue();
- add(ctx, tx, path, sport);
- }
-
- if (!updated.isEmpty()) {
- resolveIgnoredLinks(ctx, LOG);
- }
-
- return null;
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public void onFailure(VTNManagerProvider provider, Throwable t) {
- LOG.error("Failed to update VTN port information.", t);
- }
-
- // NodeConnectorEventContext
-
- /**
- * {@inheritDoc}
- */
- @Override
- public void addUpdated(InstanceIdentifier<NodeConnector> path,
- NodeConnector nc, String label) {
- SalPort sport = toSalPort(nc, label);
- if (sport != null) {
- updated.put(path, sport);
- }
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public void addRemoved(InstanceIdentifier<NodeConnector> path,
- NodeConnector nc) {
- SalPort sport = toSalPort(nc, "onRemoved");
- if (sport != null) {
- removed.put(path, sport);
- }
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public boolean hasPort() {
- return !(updated.isEmpty() && removed.isEmpty());
- }
- }
-
/**
* Construct a new instance.
*
* @param broker A {@link DataBroker} service instance.
*/
public NodeConnectorListener(TxQueue queue, DataBroker broker) {
- super(queue, broker, NodeConnector.class, DataChangeScope.BASE);
+ super(queue, broker, FlowCapableNodeConnector.class,
+ DataChangeScope.SUBTREE);
+ }
+
+ /**
+ * Add the given node connector information to the port update task.
+ *
+ * @param ectx A {@link PortUpdateTask} instance.
+ * @param path Path to the flow-capable-node-connector.
+ * @param type A {@link VtnUpdateType} instance which indicates the type
+ * of event.
+ */
+ private void addUpdated(PortUpdateTask ectx,
+ InstanceIdentifier<FlowCapableNodeConnector> path,
+ VtnUpdateType type) {
+ NodeConnectorId id = InventoryUtils.getNodeConnectorId(path);
+ SalPort sport = SalPort.create(id);
+
+ if (sport == null) {
+ Logger log = (SalPort.isLogicalPort(id))
+ ? MiscUtils.VERBOSE_LOG : LOG;
+ if (log.isDebugEnabled()) {
+ log.debug("{}: Ignore unsupported node connector event: {}",
+ type, path);
+ }
+ } else {
+ ectx.addUpdated(path, sport);
+ }
}
// DataStoreListener
* {@inheritDoc}
*/
@Override
- protected NodeConnectorEventContext enterEvent(
+ protected PortUpdateTask enterEvent(
AsyncDataChangeEvent<InstanceIdentifier<?>, DataObject> ev) {
- return new PortUpdatedTask();
+ return new PortUpdateTask(LOG);
}
/**
* {@inheritDoc}
*/
@Override
- protected void exitEvent(NodeConnectorEventContext ectx) {
- if (ectx.hasPort()) {
+ protected void exitEvent(PortUpdateTask ectx) {
+ if (ectx.hasUpdates()) {
submit(ectx);
}
}
* {@inheritDoc}
*/
@Override
- protected void onCreated(NodeConnectorEventContext ectx,
- InstanceIdentifier<NodeConnector> key,
- NodeConnector value) {
- ectx.addUpdated(key, value, "onCreated");
+ protected void onCreated(PortUpdateTask ectx,
+ InstanceIdentifier<FlowCapableNodeConnector> key,
+ FlowCapableNodeConnector value) {
+ addUpdated(ectx, key, VtnUpdateType.CREATED);
}
/**
* {@inheritDoc}
*/
@Override
- protected void onUpdated(NodeConnectorEventContext ectx,
- InstanceIdentifier<NodeConnector> key,
- NodeConnector oldValue, NodeConnector newValue) {
- ectx.addUpdated(key, newValue, "onUpdated");
+ protected void onUpdated(PortUpdateTask ectx,
+ InstanceIdentifier<FlowCapableNodeConnector> key,
+ FlowCapableNodeConnector oldValue,
+ FlowCapableNodeConnector newValue) {
+ addUpdated(ectx, key, VtnUpdateType.CHANGED);
}
/**
* {@inheritDoc}
*/
@Override
- protected void onRemoved(NodeConnectorEventContext ectx,
- InstanceIdentifier<NodeConnector> key,
- NodeConnector value) {
- ectx.addRemoved(key, value);
+ protected void onRemoved(PortUpdateTask ectx,
+ InstanceIdentifier<FlowCapableNodeConnector> key,
+ FlowCapableNodeConnector value) {
+ addUpdated(ectx, key, VtnUpdateType.REMOVED);
}
/**
* {@inheritDoc}
*/
@Override
- protected InstanceIdentifier<NodeConnector> getWildcardPath() {
+ protected InstanceIdentifier<FlowCapableNodeConnector> getWildcardPath() {
return InstanceIdentifier.builder(Nodes.class).child(Node.class).
- child(NodeConnector.class).build();
+ child(NodeConnector.class).
+ augmentation(FlowCapableNodeConnector.class).build();
}
/**
+++ /dev/null
-/*
- * Copyright (c) 2015 NEC Corporation
- * 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.vtn.manager.internal.inventory;
-
-import org.opendaylight.vtn.manager.internal.TxTask;
-
-import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
-
-import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
-
-/**
- * An event context used to handle node events.
- */
-interface NodeEventContext extends TxTask<Void> {
- /**
- * Add the given node to the node map to be created.
- *
- * @param path The identifier of the node to be added.
- * @param node A {@link Node} instance to be added.
- */
- void addCreated(InstanceIdentifier<Node> path, Node node);
-
- /**
- * Add the given node to the node map to be removed.
- *
- * @param path The identifier of the node to be added.
- * @param node A {@link Node} instance to be added.
- */
- void addRemoved(InstanceIdentifier<Node> path, Node node);
-
- /**
- * Determine whether this instance contains nodes to be created or
- * removed.
- *
- * @return {@code true} only if this instance contains at least one
- * node to be created or removed.
- */
- boolean hasNode();
-}
import java.util.Collections;
import java.util.ArrayList;
import java.util.EnumSet;
-import java.util.HashMap;
import java.util.List;
-import java.util.Map;
import java.util.Set;
import org.slf4j.Logger;
import org.opendaylight.vtn.manager.internal.TxQueue;
import org.opendaylight.vtn.manager.internal.VTNManagerProvider;
import org.opendaylight.vtn.manager.internal.util.DataStoreUtils;
-import org.opendaylight.vtn.manager.internal.util.inventory.InventoryReader;
import org.opendaylight.vtn.manager.internal.util.inventory.InventoryUtils;
import org.opendaylight.vtn.manager.internal.util.inventory.SalNode;
import org.opendaylight.vtn.manager.internal.util.tx.AbstractTxTask;
import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.impl.inventory.rev150209.vtn.nodes.VtnNode;
import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.types.rev150209.VtnUpdateType;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode;
import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes;
import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
* Listener class that listens the change of MD-SAL nodes.
*/
public final class NodeListener
- extends InventoryMaintainer<Node, NodeEventContext> {
+ extends InventoryMaintainer<FlowCapableNode, NodeUpdateTask> {
/**
* Logger instance.
*/
}
}
- /**
- * MD-SAL transaction task that creates the VTN node.
- */
- private class NodeUpdatedTask extends AbstractTxTask<Void>
- implements NodeEventContext {
- /**
- * A map that keeps created MD-SAL nodes.
- */
- private final Map<InstanceIdentifier<Node>, SalNode> created =
- new HashMap<>();
-
- /**
- * A map that keeps removed list of removed MD-SAL nodes.
- */
- private final Map<InstanceIdentifier<Node>, SalNode> removed =
- new HashMap<>();
-
- /**
- * Add the given node to the VTN inventory datastore.
- *
- * @param ctx A MD-SAL datastore transaction context.
- * @param tx A {@link ReadWriteTransaction} instance.
- * @param path Instance identifier of the created MD-SAL node.
- * @param snode A {@link SalNode} instance corresponding to the
- * created MD-SAL node.
- * @throws VTNException An error occurred.
- */
- private void add(TxContext ctx, ReadWriteTransaction tx,
- InstanceIdentifier<Node> path, SalNode snode)
- throws VTNException {
- // Read MD-SAL node from the datastore.
- LogicalDatastoreType oper = LogicalDatastoreType.OPERATIONAL;
- Node node = DataStoreUtils.read(tx, oper, path).orNull();
- if (node == null) {
- LOG.debug("Ignore bogus creation event: {}", snode);
- } else {
- // Create a VTN node.
- VtnNode vnode = InventoryUtils.toVtnNodeBuilder(node).build();
- tx.merge(oper, snode.getVtnNodeIdentifier(), vnode, true);
-
- // Cache this node into the inventory reader.
- InventoryReader reader = ctx.getInventoryReader();
- reader.prefetch(snode, vnode);
- }
- }
-
- /**
- * Remove the given node from the VTN inventory datastore.
- *
- * @param tx A {@link ReadWriteTransaction} instance.
- * @param path Instance identifier of the removed MD-SAL node.
- * @param snode A {@link SalNode} instance corresponding to the
- * removed MD-SAL node.
- * @throws VTNException An error occurred.
- */
- private void remove(ReadWriteTransaction tx,
- InstanceIdentifier<Node> path, SalNode snode)
- throws VTNException {
- // Remove VTN links affected by the removed node.
- removeVtnLink(tx, snode);
-
- // Delete a VTN node associated with the given MD-SAL node.
- DataStoreUtils.delete(tx, LogicalDatastoreType.OPERATIONAL,
- snode.getVtnNodeIdentifier());
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public Void execute(TxContext ctx) throws VTNException {
- // Process node deletion events.
- ReadWriteTransaction tx = ctx.getReadWriteTransaction();
- for (Map.Entry<InstanceIdentifier<Node>, SalNode> entry:
- removed.entrySet()) {
- InstanceIdentifier<Node> path = entry.getKey();
- SalNode snode = entry.getValue();
- remove(tx, path, snode);
- }
-
- // Process node creation events.
- for (Map.Entry<InstanceIdentifier<Node>, SalNode> entry:
- created.entrySet()) {
- InstanceIdentifier<Node> path = entry.getKey();
- SalNode snode = entry.getValue();
- add(ctx, tx, path, snode);
- }
-
- if (!created.isEmpty()) {
- // Try to resolve ignored inter-switch links.
- resolveIgnoredLinks(ctx, LOG);
- }
-
- return null;
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public void onFailure(VTNManagerProvider provider, Throwable t) {
- LOG.error("Failed to update VTN node information.", t);
- }
-
- // NodeEventContext
-
- /**
- * {@inheritDoc}
- */
- @Override
- public void addCreated(InstanceIdentifier<Node> path, Node node) {
- NodeId id = node.getId();
- SalNode snode = SalNode.create(id);
- if (snode == null) {
- LOG.debug("Ignore unsupported node creation: {}", id);
- } else {
- created.put(path, snode);
- }
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public void addRemoved(InstanceIdentifier<Node> path, Node node) {
- NodeId id = node.getId();
- SalNode snode = SalNode.create(id);
- if (snode == null) {
- LOG.debug("Ignore unsupported node deletion: {}", id);
- } else {
- removed.put(path, snode);
- }
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public boolean hasNode() {
- return !(created.isEmpty() && removed.isEmpty());
- }
- }
-
/**
* Construct a new instance.
*
* @param broker A {@link DataBroker} service instance.
*/
public NodeListener(TxQueue queue, DataBroker broker) {
- super(queue, broker, Node.class, DataChangeScope.BASE);
+ super(queue, broker, FlowCapableNode.class, DataChangeScope.SUBTREE);
submitInitial(new NodesInitTask());
}
+ /**
+ * Add the given node information to the node update task.
+ *
+ * @param ectx A {@link NodeUpdateTask} instance.
+ * @param path Path to the flow-capable-node.
+ * @param type A {@link VtnUpdateType} instance which indicates the type
+ * of event.
+ */
+ private void addUpdated(NodeUpdateTask ectx,
+ InstanceIdentifier<FlowCapableNode> path,
+ VtnUpdateType type) {
+ NodeId nid = InventoryUtils.getNodeId(path);
+ SalNode snode = SalNode.create(nid);
+ if (snode == null) {
+ LOG.debug("{}: Ignore unsupported node event: {}", type, path);
+ } else {
+ ectx.addUpdated(path, snode);
+ }
+ }
+
// DataStoreListener
/**
* {@inheritDoc}
*/
@Override
- protected NodeEventContext enterEvent(
+ protected NodeUpdateTask enterEvent(
AsyncDataChangeEvent<InstanceIdentifier<?>, DataObject> ev) {
- return new NodeUpdatedTask();
+ return new NodeUpdateTask(LOG);
}
/**
* {@inheritDoc}
*/
@Override
- protected void exitEvent(NodeEventContext ectx) {
- if (ectx.hasNode()) {
+ protected void exitEvent(NodeUpdateTask ectx) {
+ if (ectx.hasUpdates()) {
submit(ectx);
}
}
* {@inheritDoc}
*/
@Override
- protected void onCreated(NodeEventContext ectx,
- InstanceIdentifier<Node> key, Node value) {
- ectx.addCreated(key, value);
+ protected void onCreated(NodeUpdateTask ectx,
+ InstanceIdentifier<FlowCapableNode> key,
+ FlowCapableNode value) {
+ addUpdated(ectx, key, VtnUpdateType.CREATED);
}
/**
* {@inheritDoc}
*/
@Override
- protected void onUpdated(NodeEventContext ectx,
- InstanceIdentifier<Node> key, Node oldValue,
- Node newValue) {
+ protected void onUpdated(NodeUpdateTask ectx,
+ InstanceIdentifier<FlowCapableNode> key,
+ FlowCapableNode oldValue,
+ FlowCapableNode newValue) {
throw new IllegalStateException("Should never be called.");
}
* {@inheritDoc}
*/
@Override
- protected void onRemoved(NodeEventContext ectx,
- InstanceIdentifier<Node> key, Node value) {
- ectx.addRemoved(key, value);
+ protected void onRemoved(NodeUpdateTask ectx,
+ InstanceIdentifier<FlowCapableNode> key,
+ FlowCapableNode value) {
+ addUpdated(ectx, key, VtnUpdateType.REMOVED);
}
/**
* {@inheritDoc}
*/
@Override
- protected InstanceIdentifier<Node> getWildcardPath() {
+ protected InstanceIdentifier<FlowCapableNode> getWildcardPath() {
return InstanceIdentifier.builder(Nodes.class).child(Node.class).
- build();
+ augmentation(FlowCapableNode.class).build();
}
/**
--- /dev/null
+/*
+ * Copyright (c) 2015 NEC Corporation
+ * 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.vtn.manager.internal.inventory;
+
+import org.slf4j.Logger;
+
+import org.opendaylight.vtn.manager.VTNException;
+
+import org.opendaylight.vtn.manager.internal.TxContext;
+import org.opendaylight.vtn.manager.internal.VTNManagerProvider;
+import org.opendaylight.vtn.manager.internal.util.DataStoreUtils;
+import org.opendaylight.vtn.manager.internal.util.inventory.InventoryUtils;
+import org.opendaylight.vtn.manager.internal.util.inventory.SalNode;
+
+import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.impl.inventory.rev150209.vtn.nodes.VtnNode;
+
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode;
+
+/**
+ * A MD-SAL datastore transaction task that updates VTN node information.
+ */
+final class NodeUpdateTask
+ extends InventoryUpdateTask<FlowCapableNode, SalNode> {
+ /**
+ * Construct a new instance.
+ *
+ * @param log A {@link Logger} instance.
+ */
+ NodeUpdateTask(Logger log) {
+ super(log);
+ }
+
+ // InventoryUpdateTask
+
+ /**
+ * Add a VTN node information corresponding to the given MD-SAL node.
+ *
+ * @param ctx A {@link TxContext} instance.
+ * @param tx A {@link ReadWriteTransaction} instance.
+ * @param snode A {@link SalNode} instance which indicates the location
+ * of the node.
+ * @param path Path to the {@link FlowCapableNode} instance in the
+ * MD-SAL datastore.
+ * @param fcn A {@link FlowCapableNode} instance.
+ * @throws VTNException An error occurred.
+ */
+ @Override
+ protected void add(TxContext ctx, ReadWriteTransaction tx, SalNode snode,
+ InstanceIdentifier<FlowCapableNode> path,
+ FlowCapableNode fcn) throws VTNException {
+ // Create a VTN node.
+ VtnNode vnode = InventoryUtils.toVtnNodeBuilder(snode.getNodeId()).
+ build();
+ tx.merge(LogicalDatastoreType.OPERATIONAL,
+ snode.getVtnNodeIdentifier(), vnode, true);
+ }
+
+ /**
+ * Remove a VTN node information corresponding to the given MD-SAL node.
+ *
+ * @param ctx A {@link TxContext} instance.
+ * @param tx A {@link ReadWriteTransaction} instance.
+ * @param snode A {@link SalNode} instance which indicates the location
+ * of the node.
+ * @throws VTNException An error occurred.
+ */
+ @Override
+ protected void remove(TxContext ctx, ReadWriteTransaction tx,
+ SalNode snode)throws VTNException {
+ // Remove VTN links affected by the removed node.
+ InventoryUtils.removeVtnLink(tx, snode);
+
+ // Delete a VTN node associated with the given MD-SAL node.
+ DataStoreUtils.delete(tx, LogicalDatastoreType.OPERATIONAL,
+ snode.getVtnNodeIdentifier());
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected void fixUp(TxContext ctx, boolean added) {
+ // Nothing to do here.
+ }
+
+ // TxTask
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void onFailure(VTNManagerProvider provider, Throwable t) {
+ getLogger().error("Failed to update VTN node information.", t);
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2015 NEC Corporation
+ * 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.vtn.manager.internal.inventory;
+
+import org.slf4j.Logger;
+
+import org.opendaylight.vtn.manager.VTNException;
+
+import org.opendaylight.vtn.manager.internal.TxContext;
+import org.opendaylight.vtn.manager.internal.VTNManagerProvider;
+import org.opendaylight.vtn.manager.internal.util.DataStoreUtils;
+import org.opendaylight.vtn.manager.internal.util.inventory.InventoryReader;
+import org.opendaylight.vtn.manager.internal.util.inventory.InventoryUtils;
+import org.opendaylight.vtn.manager.internal.util.inventory.SalNode;
+import org.opendaylight.vtn.manager.internal.util.inventory.SalPort;
+
+import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.impl.inventory.rev150209.VtnOpenflowVersion;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.impl.inventory.rev150209.vtn.node.info.VtnPort;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.impl.inventory.rev150209.vtn.nodes.VtnNode;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.impl.inventory.rev150209.vtn.nodes.VtnNodeBuilder;
+
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNodeConnector;
+
+/**
+ * A MD-SAL datastore transaction task that updates VTN port information.
+ */
+final class PortUpdateTask
+ extends InventoryUpdateTask<FlowCapableNodeConnector, SalPort> {
+ /**
+ * Construct a new instance.
+ *
+ * @param log A {@link Logger} instance.
+ */
+ PortUpdateTask(Logger log) {
+ super(log);
+ }
+
+ // InventoryUpdateTask
+ /**
+ * Add a VTN port information corresponding to the given MD-SAL node
+ * connector.
+ *
+ * @param ctx A {@link TxContext} instance.
+ * @param tx A {@link ReadWriteTransaction} instance.
+ * @param sport A {@link SalPort} instance which indicates the location
+ * of the node connector.
+ * @param path Path to the {@link FlowCapableNodeConnector} instance in
+ * the MD-SAL datastore.
+ * @param fcnc A {@link FlowCapableNodeConnector} instance.
+ * @throws VTNException An error occurred.
+ */
+ @Override
+ protected void add(TxContext ctx, ReadWriteTransaction tx, SalPort sport,
+ InstanceIdentifier<FlowCapableNodeConnector> path,
+ FlowCapableNodeConnector fcnc) throws VTNException {
+ // Create or update a VTN port.
+ LogicalDatastoreType oper = LogicalDatastoreType.OPERATIONAL;
+ VtnPort vport = InventoryUtils.
+ toVtnPortBuilder(sport.getNodeConnectorId(), fcnc).build();
+ tx.merge(oper, sport.getVtnPortIdentifier(), vport, true);
+
+ // Read VTN node from the datastore.
+ SalNode snode = sport.getSalNode();
+ InstanceIdentifier<VtnNode> vnpath = snode.getVtnNodeIdentifier();
+ VtnNode vnode = DataStoreUtils.read(tx, oper, vnpath).orNull();
+ if (vnode == null || vnode.getOpenflowVersion() == null) {
+ // Estimate protocol version.
+ VtnOpenflowVersion v = InventoryUtils.getOpenflowVersion(fcnc);
+ VtnNode vn = new VtnNodeBuilder().setId(snode.getNodeId()).
+ setOpenflowVersion(v).build();
+ tx.merge(oper, vnpath, vn, true);
+ }
+
+ // Cache this port into the inventory reader.
+ InventoryReader reader = ctx.getInventoryReader();
+ reader.prefetch(sport, vport);
+ }
+
+ /**
+ * Remove a VTN port information corresponding to the given MD-SAL node
+ * connector.
+ *
+ * @param ctx A {@link TxContext} instance.
+ * @param tx A {@link ReadWriteTransaction} instance.
+ * @param sport A {@link SalPort} instance which indicates the location
+ * of the node connector.
+ * @throws VTNException An error occurred.
+ */
+ @Override
+ protected void remove(TxContext ctx, ReadWriteTransaction tx,
+ SalPort sport) throws VTNException {
+ LogicalDatastoreType oper = LogicalDatastoreType.OPERATIONAL;
+ InstanceIdentifier<VtnPort> vpath = sport.getVtnPortIdentifier();
+ VtnPort vport = DataStoreUtils.read(tx, oper, vpath).orNull();
+ if (vport != null) {
+ // Remove VTN links affected by the removed port.
+ InventoryUtils.removeVtnLink(tx, vport);
+
+ // Remove a VTN port.
+ tx.delete(oper, vpath);
+ }
+
+ // Add negative cache for the removed port.
+ InventoryReader reader = ctx.getInventoryReader();
+ reader.prefetch(sport, (VtnPort)null);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected void fixUp(TxContext ctx, boolean added) throws VTNException {
+ if (added) {
+ // Resolve ignored inter-switch links.
+ ReadWriteTransaction tx = ctx.getReadWriteTransaction();
+ InventoryReader reader = ctx.getInventoryReader();
+ InventoryUtils.resolveIgnoredLinks(tx, reader, getLogger());
+ }
+ }
+
+ // TxTask
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void onFailure(VTNManagerProvider provider, Throwable t) {
+ getLogger().error("Failed to update VTN port information.", t);
+ }
+}
+++ /dev/null
-/*
- * Copyright (c) 2015 NEC Corporation
- * 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.vtn.manager.internal.inventory;
-
-import org.opendaylight.vtn.manager.internal.TxTask;
-
-import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Link;
-
-/**
- * An event context used to handle topology events.
- */
-interface TopologyEventContext extends TxTask<Void> {
- /**
- * Add the given link to the link map to be created.
- *
- * @param link A {@link Link} instance to be added.
- */
- void addCreated(Link link);
-
- /**
- * Add the given link to the link map to be removed.
- *
- * @param link A {@link Link} instance to be added.
- */
- void addRemoved(Link link);
-
- /**
- * Determine whether this instance contains at least one link information
- * to be created or removed.
- *
- * @return {@code true} only if this instance contains at least one
- * link information to be created or removed.
- */
- boolean hasLink();
-}
import java.util.Collections;
import java.util.EnumSet;
-import java.util.HashMap;
import java.util.List;
-import java.util.Map;
import java.util.Set;
import org.slf4j.Logger;
import org.opendaylight.vtn.manager.internal.TxQueue;
import org.opendaylight.vtn.manager.internal.VTNManagerProvider;
import org.opendaylight.vtn.manager.internal.util.DataStoreUtils;
+import org.opendaylight.vtn.manager.internal.util.inventory.InventoryReader;
import org.opendaylight.vtn.manager.internal.util.inventory.InventoryUtils;
-import org.opendaylight.vtn.manager.internal.util.inventory.LinkEdge;
import org.opendaylight.vtn.manager.internal.util.inventory.SalPort;
import org.opendaylight.vtn.manager.internal.util.tx.AbstractTxTask;
import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.impl.topology.rev150209.IgnoredLinksBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.impl.topology.rev150209.VtnTopology;
import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.impl.topology.rev150209.VtnTopologyBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.impl.topology.rev150209.ignored.links.IgnoredLink;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.impl.topology.rev150209.vtn.topology.VtnLink;
import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.types.rev150209.VtnUpdateType;
import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.LinkId;
* Listener class that listens the change of MD-SAL topology datastore.
*/
public final class TopologyListener
- extends InventoryMaintainer<Link, TopologyEventContext> {
+ extends InventoryMaintainer<Link, LinkUpdateTask> {
/**
* Logger instance.
*/
/**
* MD-SAL transaction task that initializes the VTN topology tree.
*/
- private class TopologyInitTask extends AbstractTxTask<Void> {
+ private static class TopologyInitTask extends AbstractTxTask<Void> {
/**
* Initialize VTN network topology.
*
* @param tx A {@link ReadWriteTransaction} instance.
+ * @param reader An {@link InventoryReader} instance.
* @param topology MD-SAL network topology.
* @throws VTNException
* An error occurred.
*/
- private void initLinks(ReadWriteTransaction tx, Topology topology)
+ private void initLinks(ReadWriteTransaction tx, InventoryReader reader,
+ Topology topology)
throws VTNException {
if (topology == null) {
return;
}
LinkId lid = link.getLinkId();
- if (!addVtnLink(tx, lid, src, dst)) {
+ if (!InventoryUtils.addVtnLink(tx, reader, lid, src, dst)) {
LOG.warn("Ignore inter-switch link: {}: {} -> {}",
lid.getValue(), src, dst);
}
tx.delete(oper, igPath);
tx.merge(oper, vtPath, new VtnTopologyBuilder().build(), true);
tx.merge(oper, igPath, new IgnoredLinksBuilder().build(), true);
- initLinks(tx, topology);
+ initLinks(tx, ctx.getInventoryReader(), topology);
return null;
}
}
}
- /**
- * MD-SAL transaction task that updates the VTN link.
- */
- private class LinkUpdatedTask extends AbstractTxTask<Void>
- implements TopologyEventContext {
- /**
- * A map that keeps created links.
- */
- private final Map<LinkId, LinkEdge> created = new HashMap<>();
-
- /**
- * A map that keeps removed links.
- */
- private final Map<LinkId, LinkEdge> removed = new HashMap<>();
-
- /**
- * Remove the given link from the VTN network topology.
- *
- * @param tx A {@link ReadWriteTransaction} instance.
- * @param lid A {@link LinkId} instance.
- * @param le A {@link LinkEdge} instance.
- * @throws VTNException An error occurred.
- */
- private void remove(ReadWriteTransaction tx, LinkId lid, LinkEdge le)
- throws VTNException {
- // Remove the link from vtn-topology list.
- SalPort src = le.getSourcePort();
- SalPort dst = le.getDestinationPort();
- LogicalDatastoreType oper = LogicalDatastoreType.OPERATIONAL;
- InstanceIdentifier<VtnLink> lpath =
- InventoryUtils.toVtnLinkIdentifier(lid);
- if (DataStoreUtils.read(tx, oper, lpath).isPresent()) {
- tx.delete(oper, lpath);
-
- // Remove port links.
- removePortLink(tx, src, lid);
- removePortLink(tx, dst, lid);
- } else {
- // Remove the link from ignored-links list.
- InstanceIdentifier<IgnoredLink> ipath =
- InventoryUtils.toIgnoredLinkIdentifier(lid);
- DataStoreUtils.delete(tx, oper, ipath);
- }
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public Void execute(TxContext ctx) throws VTNException {
- // Process link deletion events.
- ReadWriteTransaction tx = ctx.getReadWriteTransaction();
- for (Map.Entry<LinkId, LinkEdge> entry: removed.entrySet()) {
- LinkId lid = entry.getKey();
- LinkEdge le = entry.getValue();
- remove(tx, lid, le);
- }
-
- // Process link creation events.
- for (Map.Entry<LinkId, LinkEdge> entry: created.entrySet()) {
- LinkId lid = entry.getKey();
- LinkEdge le = entry.getValue();
- SalPort src = le.getSourcePort();
- SalPort dst = le.getDestinationPort();
- if (!addVtnLink(tx, lid, src, dst)) {
- LOG.warn("onCreated: Ignore inter-switch link: {}: " +
- "{} -> {}", lid.getValue(), src, dst);
- }
- }
-
- return null;
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public void onFailure(VTNManagerProvider provider, Throwable t) {
- LOG.error("Failed to update VTN link.", t);
- }
-
- // TopologyEventContext
-
- /**
- * {@inheritDoc}
- */
- @Override
- public void addCreated(Link link) {
- LinkId lid = link.getLinkId();
- LinkEdge le = new LinkEdge(link);
- created.put(lid, le);
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public void addRemoved(Link link) {
- LinkId lid = link.getLinkId();
- LinkEdge le = new LinkEdge(link);
- removed.put(lid, le);
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public boolean hasLink() {
- return !(created.isEmpty() && removed.isEmpty());
- }
- }
-
/**
* Construct a new instance.
*
* {@inheritDoc}
*/
@Override
- protected TopologyEventContext enterEvent(
+ protected LinkUpdateTask enterEvent(
AsyncDataChangeEvent<InstanceIdentifier<?>, DataObject> ev) {
- return new LinkUpdatedTask();
+ return new LinkUpdateTask(LOG);
}
/**
* {@inheritDoc}
*/
@Override
- protected void exitEvent(TopologyEventContext ectx) {
- if (ectx.hasLink()) {
+ protected void exitEvent(LinkUpdateTask ectx) {
+ if (ectx.hasUpdates()) {
submit(ectx);
}
}
* {@inheritDoc}
*/
@Override
- protected void onCreated(TopologyEventContext ectx,
- InstanceIdentifier<Link> key, Link value) {
- try {
- ectx.addCreated(value);
- } catch (IllegalArgumentException e) {
- LOG.debug("Ignore unsupported inter-switch link creation: " +
- value, e);
- }
+ protected void onCreated(LinkUpdateTask ectx, InstanceIdentifier<Link> key,
+ Link value) {
+ ectx.addUpdated(key);
}
/**
* {@inheritDoc}
*/
@Override
- protected void onUpdated(TopologyEventContext ectx,
- InstanceIdentifier<Link> key, Link oldValue,
- Link newValue) {
+ protected void onUpdated(LinkUpdateTask ectx, InstanceIdentifier<Link> key,
+ Link oldValue, Link newValue) {
throw new IllegalStateException("Should never be called.");
}
* {@inheritDoc}
*/
@Override
- protected void onRemoved(TopologyEventContext ectx,
- InstanceIdentifier<Link> key, Link value) {
- try {
- ectx.addRemoved(value);
- } catch (IllegalArgumentException e) {
- LOG.debug("Ignore unsupported inter-switch link deletion: " +
- value, e);
- }
+ protected void onRemoved(LinkUpdateTask ectx, InstanceIdentifier<Link> key,
+ Link value) {
+ ectx.addUpdated(key);
}
/**
import java.util.Collection;
import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
import org.opendaylight.vtn.manager.VTNException;
import org.opendaylight.vtn.manager.util.EtherAddress;
* methods.
*/
public final class MiscUtils {
+ /**
+ * A logger for extra verbose logging.
+ */
+ public static final Logger VERBOSE_LOG =
+ LoggerFactory.getLogger("ODL-VTN-Manager-verbose");
+
+ /**
+ * A prime number used to calculate hash code.
+ */
+ public static final int HASH_PRIME = 31;
+
/**
* Private constructor that protects this class from instantiating.
*/
import java.util.ArrayList;
import java.util.List;
+import com.google.common.base.Optional;
+
+import org.slf4j.Logger;
+
+import org.opendaylight.vtn.manager.VTNException;
+
+import org.opendaylight.vtn.manager.internal.util.DataStoreUtils;
+
+import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+
import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.impl.inventory.rev150209.VtnOpenflowVersion;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.port.rev130925.PortFeatures;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.port.rev130925.flow.capable.port.State;
import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnector;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnectorKey;
import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey;
import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.LinkId;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Link;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.LinkKey;
/**
* {@code InventoryUtils} class is a collection of utility class methods
return builder.setId(node.getId());
}
+ /**
+ * Create a VTN node builder associated with the given MD-SAL node ID.
+ *
+ * @param nid A MD-SAL node ID.
+ * @return A VTN node builder.
+ */
+ public static VtnNodeBuilder toVtnNodeBuilder(NodeId nid) {
+ return new VtnNodeBuilder().setId(nid);
+ }
+
/**
* Create a VTN port builder associated with the given MD-SAL node
* connector ID.
*
- * @param nc A {@link NodeConnector} instance.
+ * @param ncid A MD-SAL node connector ID.
+ * @param fcnc A {@link FlowCapableNodeConnector} instance.
* @return A VTN port builder.
*/
- public static VtnPortBuilder toVtnPortBuilder(NodeConnector nc) {
- VtnPortBuilder builder = new VtnPortBuilder();
- builder.setId(nc.getId());
+ public static VtnPortBuilder toVtnPortBuilder(
+ NodeConnectorId ncid, FlowCapableNodeConnector fcnc) {
+ VtnPortBuilder builder = new VtnPortBuilder().setId(ncid);
+ String name = fcnc.getName();
+ PortFeatures pf = fcnc.getCurrentFeature();
+ Long curSpeed = fcnc.getCurrentSpeed();
+ PortConfig pcfg = fcnc.getConfiguration();
+ Boolean portDown = (pcfg == null) ? null : pcfg.isPORTDOWN();
+ State state = fcnc.getState();
+ Boolean linkDown = (state == null) ? null : state.isLinkDown();
- FlowCapableNodeConnector fcnc =
- nc.getAugmentation(FlowCapableNodeConnector.class);
- String name = null;
boolean enabled = false;
- PortFeatures pf = null;
- Long curSpeed = null;
- if (fcnc != null) {
- name = fcnc.getName();
- PortConfig pcfg = fcnc.getConfiguration();
- Boolean portDown = null;
- if (pcfg != null) {
- portDown = pcfg.isPORTDOWN();
- }
-
- State state = fcnc.getState();
- Boolean linkDown = null;
- if (state != null) {
- linkDown = state.isLinkDown();
- }
-
- if (Boolean.FALSE.equals(portDown) &&
- Boolean.FALSE.equals(linkDown)) {
- enabled = true;
- }
-
- pf = fcnc.getCurrentFeature();
- curSpeed = fcnc.getCurrentSpeed();
+ if (Boolean.FALSE.equals(portDown) && Boolean.FALSE.equals(linkDown)) {
+ enabled = true;
}
// Determine the cost of the link from the link speed.
if (name == null) {
// Port name is unavailable.
// Use node-connector-id instead.
- name = nc.getId().getValue();
+ name = ncid.getValue();
}
builder.setName(name).setEnabled(Boolean.valueOf(enabled)).
for (NodeConnector nc: connectors) {
NodeConnectorId id = nc.getId();
SalPort sport = SalPort.create(id);
- if (sport != null) {
- VtnPort vport = toVtnPortBuilder(nc).build();
+ if (sport == null) {
+ continue;
+ }
+
+ FlowCapableNodeConnector fcnc =
+ nc.getAugmentation(FlowCapableNodeConnector.class);
+ if (fcnc != null) {
+ VtnPort vport = toVtnPortBuilder(id, fcnc).build();
list.add(vport);
if (version == null) {
- version = getOpenflowVersion(nc);
+ version = getOpenflowVersion(fcnc);
}
}
}
* Estimate the OpenFlow protocol version from the given
* {@link NodeConnector} instance.
*
- * @param nc A {@link NodeConnector} instance.
+ * @param fcnc A {@link FlowCapableNodeConnector} instance.
* @return Estimated OpenFlow protocol version number.
*/
- public static VtnOpenflowVersion getOpenflowVersion(NodeConnector nc) {
- FlowCapableNodeConnector fcnc =
- nc.getAugmentation(FlowCapableNodeConnector.class);
- if (fcnc != null) {
- if (fcnc.getCurrentSpeed() != null) {
- // OpenFlow 1.3 PORT_STATUS message contains the current
- // link speed of the port, but OpenFlow 1.0 does not.
- return VtnOpenflowVersion.OF13;
- }
+ public static VtnOpenflowVersion getOpenflowVersion(
+ FlowCapableNodeConnector fcnc) {
+ if (fcnc != null && fcnc.getCurrentSpeed() != null) {
+ // OpenFlow 1.3 PORT_STATUS message contains the current
+ // link speed of the port, but OpenFlow 1.0 does not.
+ return VtnOpenflowVersion.OF13;
}
return VtnOpenflowVersion.OF10;
// Use 1Gbps as default.
return LINK_SPEED_1G;
}
+
+ /**
+ * Return a MD-SAL node ID in the given instance identifier.
+ *
+ * @param path An {@link InstanceIdentifier} instance.
+ * @return A MD-SAL node ID if found.
+ * {@code null} if not found.
+ */
+ public static NodeId getNodeId(InstanceIdentifier<?> path) {
+ NodeKey key = path.firstKeyOf(Node.class, NodeKey.class);
+ return (key == null) ? null : key.getId();
+ }
+
+ /**
+ * Return a MD-SAL node connector ID in the given instance identifier.
+ *
+ * @param path An {@link InstanceIdentifier} instance.
+ * @return A MD-SAL node connector ID if found.
+ * {@code null} if not found.
+ */
+ public static NodeConnectorId getNodeConnectorId(
+ InstanceIdentifier<?> path) {
+ NodeConnectorKey key =
+ path.firstKeyOf(NodeConnector.class, NodeConnectorKey.class);
+ return (key == null) ? null : key.getId();
+ }
+
+ /**
+ * Return a MD-SAL inter-switch link ID in the given instance identifier.
+ *
+ * @param path An {@link InstanceIdentifier} instance.
+ * @return A MD-SAL inter-switch link ID if found.
+ * {@code null} if not found.
+ */
+ public static LinkId getLinkId(InstanceIdentifier<?> path) {
+ LinkKey key = path.firstKeyOf(Link.class, LinkKey.class);
+ return (key == null) ? null : key.getLinkId();
+ }
+
+ /**
+ * Add the given inter-switch link information into the VTN inventory data.
+ *
+ * @param tx A {@link ReadWriteTransaction} instance.
+ * @param reader An {@link InventoryReader} instance.
+ * @param lid The identifier of the created link.
+ * @param src A {@link SalPort} instance corresponding to the source
+ * of the created link.
+ * @param dst A {@link SalPort} instance corresponding to the
+ * destination of the created link.
+ * @return {@code true} if the link was added to the vtn-topology list.
+ * {@code false} if the link was added to the ignored-links list.
+ * @throws VTNException An error occurred.
+ */
+ public static boolean addVtnLink(ReadWriteTransaction tx,
+ InventoryReader reader, LinkId lid,
+ SalPort src, SalPort dst)
+ throws VTNException {
+ // Determine whether the VTN port for both termination points are
+ // present or not.
+ boolean ret;
+ if (reader.get(src) != null && reader.get(dst) != null) {
+ // Create link information.
+ createVtnLink(tx, lid, src, dst);
+ ret = true;
+ } else {
+ // Put link information into ignored link list.
+ InstanceIdentifier<IgnoredLink> key = toIgnoredLinkIdentifier(lid);
+ IgnoredLink ilink = toIgnoredLinkBuilder(lid, src, dst).build();
+ tx.merge(LogicalDatastoreType.OPERATIONAL, key, ilink, true);
+ ret = false;
+ }
+
+ return ret;
+ }
+
+
+ /**
+ * Create a VTN link information, and put it into the MD-SAL datastore.
+ *
+ * @param tx A {@link ReadWriteTransaction} instance.
+ * @param lid The identifier of the created link.
+ * @param src A {@link SalPort} instance corresponding to the source
+ * of the created link.
+ * @param dst A {@link SalPort} instance corresponding to the destination
+ * of the created link.
+ */
+ public static void createVtnLink(ReadWriteTransaction tx, LinkId lid,
+ SalPort src, SalPort dst) {
+ // Put the link information into vtn-topology list.
+ InstanceIdentifier<VtnLink> key = toVtnLinkIdentifier(lid);
+ VtnLink vlink = toVtnLinkBuilder(lid, src, dst).build();
+ LogicalDatastoreType oper = LogicalDatastoreType.OPERATIONAL;
+ tx.merge(oper, key, vlink, true);
+
+ // Create source port link.
+ InstanceIdentifier<PortLink> pkey = src.getPortLinkIdentifier(lid);
+ PortLink plink = toPortLinkBuilder(lid, dst).build();
+ tx.merge(oper, pkey, plink, true);
+
+ // Create destination port link.
+ pkey = dst.getPortLinkIdentifier(lid);
+ plink = toPortLinkBuilder(lid, src).build();
+ tx.merge(oper, pkey, plink, true);
+ }
+
+ /**
+ * Remove all VTN links affected by the the removed VTN node.
+ *
+ * @param tx A {@link ReadWriteTransaction} instance.
+ * @param snode A {@link SalNode} instance corresponding to the removed
+ * VTN node.
+ * @throws VTNException An error occurred.
+ */
+ public static void removeVtnLink(ReadWriteTransaction tx, SalNode snode)
+ throws VTNException {
+ removeVtnTopologyLink(tx, snode);
+ removeIgnoredLink(tx, snode);
+ }
+
+ /**
+ * Remove all VTN links in vtn-topology affected by the removed VTN node.
+ *
+ * @param tx A {@link ReadWriteTransaction} instance.
+ * @param snode A {@link SalNode} instance corresponding to the removed
+ * VTN node.
+ * @throws VTNException An error occurred.
+ */
+ public static void removeVtnTopologyLink(ReadWriteTransaction tx,
+ SalNode snode)
+ throws VTNException {
+ InstanceIdentifier<VtnTopology> topoPath =
+ InstanceIdentifier.create(VtnTopology.class);
+ LogicalDatastoreType oper = LogicalDatastoreType.OPERATIONAL;
+ Optional<VtnTopology> opt = DataStoreUtils.read(tx, oper, topoPath);
+ if (!opt.isPresent()) {
+ return;
+ }
+
+ List<VtnLink> links = opt.get().getVtnLink();
+ if (links == null) {
+ return;
+ }
+
+ long dpid = snode.getNodeNumber();
+ for (VtnLink vlink: links) {
+ LinkId lid = vlink.getLinkId();
+ SalPort src = SalPort.create(vlink.getSource());
+ SalPort dst = SalPort.create(vlink.getDestination());
+ long srcDpid = src.getNodeNumber();
+ long dstDpid = dst.getNodeNumber();
+
+ boolean rmLink = false;
+ if (srcDpid == dpid) {
+ rmLink = true;
+ if (dstDpid != dpid) {
+ removePortLink(tx, dst, lid);
+ }
+ } else if (dstDpid == dpid) {
+ rmLink = true;
+ removePortLink(tx, src, lid);
+ }
+
+ if (rmLink) {
+ InstanceIdentifier<VtnLink> lpath = toVtnLinkIdentifier(lid);
+ tx.delete(oper, lpath);
+ }
+ }
+ }
+
+ /**
+ * Remove all VTN links in ignored-links affected by the removed VTN node.
+ *
+ * @param tx A {@link ReadWriteTransaction} instance.
+ * @param snode A {@link SalNode} instance corresponding to the removed
+ * VTN node.
+ * @throws VTNException An error occurred.
+ */
+ public static void removeIgnoredLink(ReadWriteTransaction tx,
+ SalNode snode) throws VTNException {
+ InstanceIdentifier<IgnoredLinks> igPath =
+ InstanceIdentifier.create(IgnoredLinks.class);
+ LogicalDatastoreType oper = LogicalDatastoreType.OPERATIONAL;
+ Optional<IgnoredLinks> opt = DataStoreUtils.read(tx, oper, igPath);
+ if (!opt.isPresent()) {
+ return;
+ }
+
+ List<IgnoredLink> links = opt.get().getIgnoredLink();
+ if (links == null) {
+ return;
+ }
+
+ long dpid = snode.getNodeNumber();
+ for (IgnoredLink vlink: links) {
+ LinkId lid = vlink.getLinkId();
+ SalPort src = SalPort.create(vlink.getSource());
+ SalPort dst = SalPort.create(vlink.getDestination());
+ long srcDpid = src.getNodeNumber();
+ long dstDpid = dst.getNodeNumber();
+
+ if (srcDpid == dpid || dstDpid == dpid) {
+ InstanceIdentifier<IgnoredLink> lpath =
+ InventoryUtils.toIgnoredLinkIdentifier(lid);
+ tx.delete(LogicalDatastoreType.OPERATIONAL, lpath);
+ }
+ }
+ }
+
+ /**
+ * Remove all VTN links affected by the removed VTN port.
+ *
+ * @param tx A {@link ReadWriteTransaction} instance.
+ * @param vport A {@link VtnPort} instance corresponding to the removed
+ * VTN port.
+ * @throws VTNException An error occurred.
+ */
+ public static void removeVtnLink(ReadWriteTransaction tx, VtnPort vport)
+ throws VTNException {
+ List<PortLink> links = vport.getPortLink();
+ if (links == null) {
+ return;
+ }
+
+ for (PortLink plink: links) {
+ LinkId lid = plink.getLinkId();
+ NodeConnectorId peer = plink.getPeer();
+ SalPort p = SalPort.create(peer);
+ removePortLink(tx, p, lid);
+
+ InstanceIdentifier<VtnLink> lpath = toVtnLinkIdentifier(lid);
+ DataStoreUtils.delete(tx, LogicalDatastoreType.OPERATIONAL, lpath);
+ }
+ }
+
+ /**
+ * Remove the specified port link.
+ *
+ * @param tx A {@link ReadWriteTransaction} instance.
+ * @param sport A {@link SalPort} instance corresponding to a VTN port.
+ * @param lid A {@link LinkId} that specifies inter-switch link to be
+ * removed.
+ * @throws VTNException An error occurred.
+ */
+ public static void removePortLink(ReadWriteTransaction tx, SalPort sport,
+ LinkId lid) throws VTNException {
+ InstanceIdentifier<PortLink> path = sport.getPortLinkIdentifier(lid);
+ DataStoreUtils.delete(tx, LogicalDatastoreType.OPERATIONAL, path);
+ }
+
+ /**
+ * Try to resolve ignored inter-switch links.
+ *
+ * @param tx A {@link ReadWriteTransaction} instance.
+ * @param reader An {@link InventoryReader} instance.
+ * @param log A {@link Logger} instance.
+ * @throws VTNException An error occurred.
+ */
+ public static void resolveIgnoredLinks(ReadWriteTransaction tx,
+ InventoryReader reader,
+ Logger log) throws VTNException {
+ // Read all ignored inter-switch links.
+ InstanceIdentifier<IgnoredLinks> igPath =
+ InstanceIdentifier.create(IgnoredLinks.class);
+ LogicalDatastoreType oper = LogicalDatastoreType.OPERATIONAL;
+ Optional<IgnoredLinks> opt = DataStoreUtils.read(tx, oper, igPath);
+ if (!opt.isPresent()) {
+ return;
+ }
+
+ List<IgnoredLink> links = opt.get().getIgnoredLink();
+ if (links == null) {
+ return;
+ }
+
+ for (IgnoredLink ignored: links) {
+ SalPort src = SalPort.create(ignored.getSource());
+ SalPort dst = SalPort.create(ignored.getDestination());
+ if (reader.get(src) != null && reader.get(dst) != null) {
+ // Move this link to vtn-topology.
+ LinkId lid = ignored.getLinkId();
+ InstanceIdentifier<IgnoredLink> ipath =
+ toIgnoredLinkIdentifier(lid);
+ tx.delete(oper, ipath);
+ createVtnLink(tx, lid, src, dst);
+ log.info("Inter-switch link has been resolved: {}: {} -> {}",
+ lid.getValue(), src, dst);
+ }
+ }
+ }
}
package org.opendaylight.vtn.manager.internal.util.inventory;
+import org.opendaylight.vtn.manager.internal.util.MiscUtils;
+
import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.impl.topology.rev150209.vtn.topology.VtnLink;
import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Link;
*/
@Override
public int hashCode() {
- return sourcePort.hashCode() + destinationPort.hashCode() * 31;
+ return sourcePort.hashCode() +
+ destinationPort.hashCode() * MiscUtils.HASH_PRIME;
}
/**
package org.opendaylight.vtn.manager.internal.util.inventory;
import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.slf4j.Logger;
import org.junit.Test;
+import org.mockito.Mockito;
+
import org.opendaylight.vtn.manager.internal.TestBase;
+import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+
import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.IdentifiableItem;
import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.Item;
import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.PathArgument;
import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.impl.inventory.rev150209.VtnNodes;
import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.impl.inventory.rev150209.VtnOpenflowVersion;
import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.impl.inventory.rev150209.vtn.node.info.VtnPort;
import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.impl.inventory.rev150209.vtn.node.info.VtnPortBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.impl.inventory.rev150209.vtn.nodes.VtnNodeBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.impl.inventory.rev150209.vtn.port.info.PortLink;
import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.impl.inventory.rev150209.vtn.port.info.PortLinkBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.impl.inventory.rev150209.vtn.port.info.PortLinkKey;
import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.impl.topology.rev150209.IgnoredLinks;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.impl.topology.rev150209.IgnoredLinksBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.impl.topology.rev150209.VtnTopology;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.impl.topology.rev150209.VtnTopologyBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.impl.topology.rev150209.ignored.links.IgnoredLink;
import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.impl.topology.rev150209.ignored.links.IgnoredLinkBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.impl.topology.rev150209.ignored.links.IgnoredLinkKey;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.port.rev130925.flow.capable.port.StateBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId;
import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes;
import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnector;
import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnectorBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnectorKey;
import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey;
+
import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.LinkId;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NetworkTopology;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.TopologyId;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.Topology;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.TopologyKey;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Link;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.LinkKey;
/**
* JUnit test for {@link InventoryUtils}.
*/
public class InventoryUtilsTest extends TestBase {
+ /**
+ * Network topology identifier.
+ */
+ private static final String TOPOLOGY_ID = "flow:1";
+
/**
* Test case for the following methods.
*
}
/**
- * Test case for {@link InventoryUtils#toVtnNodeBuilder(Node)} and
- * {@link InventoryUtils#getVtnPorts(List, Node)}.
+ * Test case for the following methods.
+ *
+ * <ul>
+ * <li>{@link InventoryUtils#toVtnNodeBuilder(Node)}</li>
+ * <li>{@link InventoryUtils#toVtnNodeBuilder(NodeId)}</li>
+ * <li>{@link InventoryUtils#getVtnPorts(List, Node)}</li>
+ * </ul>
*/
@Test
public void testToVtnNodeBuilder() {
NodeId nodeId = new NodeId(nid);
builder.setId(nodeId);
+ vbuilder = InventoryUtils.toVtnNodeBuilder(nodeId);
+ assertEquals(nodeId, vbuilder.getId());
+ assertEquals(null, vbuilder.getVtnPort());
+ assertEquals(null, vbuilder.getOpenflowVersion());
+
List<NodeConnector> nclist10 = new ArrayList<>(badNcList);
List<NodeConnector> nclist13 = new ArrayList<>(badNcList);
List<VtnPort> vports10 = new ArrayList<>();
}
/**
- * Test case for {@link InventoryUtils#toVtnPortBuilder(NodeConnector)}.
+ * Test case for
+ * {@link InventoryUtils#toVtnPortBuilder(NodeConnectorId, FlowCapableNodeConnector)}.
*/
@Test
public void testToVtnPortBuilder() {
String pid = "openflow:" + dpid + ":" + port;
NodeConnectorId ncid = new NodeConnectorId(pid);
VtnPortKey key = new VtnPortKey(ncid);
- NodeConnectorBuilder ncBuilder = new NodeConnectorBuilder().
- setId(ncid);
- NodeConnector nc = ncBuilder.build();
- VtnPort vport = InventoryUtils.toVtnPortBuilder(nc).build();
- assertEquals(ncid, vport.getId());
- assertEquals(key, vport.getKey());
- assertEquals(pid, vport.getName());
- assertEquals(null, vport.getPortLink());
- assertEquals(Boolean.FALSE, vport.isEnabled());
- assertEquals(defCost, vport.getCost());
FlowCapableNodeConnectorBuilder fcb =
new FlowCapableNodeConnectorBuilder();
FlowCapableNodeConnector fcnc = fcb.build();
- nc = ncBuilder.
- addAugmentation(FlowCapableNodeConnector.class, fcnc).
+ VtnPort vport = InventoryUtils.toVtnPortBuilder(ncid, fcnc).
build();
- vport = InventoryUtils.toVtnPortBuilder(nc).build();
assertEquals(ncid, vport.getId());
assertEquals(key, vport.getKey());
assertEquals(pid, vport.getName());
// Set port name.
String name = "switch-" + dpid + "-port-" + port;
fcnc = fcb.setName(name).build();
- nc = ncBuilder.
- addAugmentation(FlowCapableNodeConnector.class, fcnc).
- build();
- vport = InventoryUtils.toVtnPortBuilder(nc).build();
+ vport = InventoryUtils.toVtnPortBuilder(ncid, fcnc).build();
assertEquals(ncid, vport.getId());
assertEquals(key, vport.getKey());
assertEquals(name, vport.getName());
PortConfigBuilder pcfb = new PortConfigBuilder();
PortConfig pcf = pcfb.build();
fcnc = fcb.setConfiguration(pcf).build();
- nc = ncBuilder.
- addAugmentation(FlowCapableNodeConnector.class, fcnc).
- build();
- vport = InventoryUtils.toVtnPortBuilder(nc).build();
+ vport = InventoryUtils.toVtnPortBuilder(ncid, fcnc).build();
assertEquals(ncid, vport.getId());
assertEquals(key, vport.getKey());
assertEquals(name, vport.getName());
pcf = pcfb.setNoFwd(Boolean.TRUE).setNoPacketIn(Boolean.TRUE).
setNoRecv(Boolean.TRUE).setPortDown(Boolean.TRUE).build();
fcnc = fcb.setConfiguration(pcf).build();
- nc = ncBuilder.
- addAugmentation(FlowCapableNodeConnector.class, fcnc).
- build();
- vport = InventoryUtils.toVtnPortBuilder(nc).build();
+ vport = InventoryUtils.toVtnPortBuilder(ncid, fcnc).build();
assertEquals(ncid, vport.getId());
assertEquals(key, vport.getKey());
assertEquals(name, vport.getName());
StateBuilder stb = new StateBuilder();
State st = stb.build();
fcnc = fcb.setState(st).build();
- nc = ncBuilder.
- addAugmentation(FlowCapableNodeConnector.class, fcnc).
- build();
- vport = InventoryUtils.toVtnPortBuilder(nc).build();
+ vport = InventoryUtils.toVtnPortBuilder(ncid, fcnc).build();
assertEquals(ncid, vport.getId());
assertEquals(key, vport.getKey());
assertEquals(name, vport.getName());
st = stb.setBlocked(Boolean.TRUE).setLive(Boolean.TRUE).
setLinkDown(Boolean.TRUE).build();
fcnc = fcb.setState(st).build();
- nc = ncBuilder.
- addAugmentation(FlowCapableNodeConnector.class, fcnc).
- build();
- vport = InventoryUtils.toVtnPortBuilder(nc).build();
+ vport = InventoryUtils.toVtnPortBuilder(ncid, fcnc).build();
assertEquals(ncid, vport.getId());
assertEquals(key, vport.getKey());
assertEquals(name, vport.getName());
st = stb.setLinkDown(Boolean.FALSE).build();
fcnc = fcb.setState(st).build();
- nc = ncBuilder.
- addAugmentation(FlowCapableNodeConnector.class, fcnc).
- build();
- vport = InventoryUtils.toVtnPortBuilder(nc).build();
+ vport = InventoryUtils.toVtnPortBuilder(ncid, fcnc).build();
assertEquals(ncid, vport.getId());
assertEquals(key, vport.getKey());
assertEquals(name, vport.getName());
pcf = pcfb.setPortDown(Boolean.FALSE).build();
st = stb.setLinkDown(Boolean.TRUE).build();
fcnc = fcb.setState(st).setConfiguration(pcf).build();
- nc = ncBuilder.
- addAugmentation(FlowCapableNodeConnector.class, fcnc).
- build();
- vport = InventoryUtils.toVtnPortBuilder(nc).build();
+ vport = InventoryUtils.toVtnPortBuilder(ncid, fcnc).build();
assertEquals(ncid, vport.getId());
assertEquals(key, vport.getKey());
assertEquals(name, vport.getName());
st = stb.setLinkDown(Boolean.FALSE).build();
fcnc = fcb.setState(st).build();
- nc = ncBuilder.
- addAugmentation(FlowCapableNodeConnector.class, fcnc).
- build();
- vport = InventoryUtils.toVtnPortBuilder(nc).build();
+ vport = InventoryUtils.toVtnPortBuilder(ncid, fcnc).build();
assertEquals(ncid, vport.getId());
assertEquals(key, vport.getKey());
assertEquals(name, vport.getName());
PortFeatures pf = pfb.setTenMbHd(Boolean.TRUE).build();
Long cost = Long.valueOf(base / 10000000L);
fcnc = fcb.setCurrentFeature(pf).build();
- nc = ncBuilder.
- addAugmentation(FlowCapableNodeConnector.class, fcnc).
- build();
- vport = InventoryUtils.toVtnPortBuilder(nc).build();
+ vport = InventoryUtils.toVtnPortBuilder(ncid, fcnc).build();
assertEquals(ncid, vport.getId());
assertEquals(key, vport.getKey());
assertEquals(name, vport.getName());
build();
cost = Long.valueOf(base / 10000000000L);
fcnc = fcb.setCurrentFeature(pf).build();
- nc = ncBuilder.
- addAugmentation(FlowCapableNodeConnector.class, fcnc).
- build();
- vport = InventoryUtils.toVtnPortBuilder(nc).build();
+ vport = InventoryUtils.toVtnPortBuilder(ncid, fcnc).build();
assertEquals(ncid, vport.getId());
assertEquals(key, vport.getKey());
assertEquals(name, vport.getName());
build();
cost = Long.valueOf(base / 1000000000000L);
fcnc = fcb.setCurrentFeature(pf).build();
- nc = ncBuilder.
- addAugmentation(FlowCapableNodeConnector.class, fcnc).
- build();
- vport = InventoryUtils.toVtnPortBuilder(nc).build();
+ vport = InventoryUtils.toVtnPortBuilder(ncid, fcnc).build();
assertEquals(ncid, vport.getId());
assertEquals(key, vport.getKey());
assertEquals(name, vport.getName());
long speed = 100000000L;
cost = Long.valueOf(base / speed);
fcnc = fcb.setCurrentSpeed(speed / 1000L).build();
- nc = ncBuilder.
- addAugmentation(FlowCapableNodeConnector.class, fcnc).
- build();
- vport = InventoryUtils.toVtnPortBuilder(nc).build();
+ vport = InventoryUtils.toVtnPortBuilder(ncid, fcnc).build();
assertEquals(ncid, vport.getId());
assertEquals(key, vport.getKey());
assertEquals(name, vport.getName());
speed = (long)0xffffffffL;
cost = Long.valueOf(base / (speed * 1000L));
fcnc = fcb.setCurrentSpeed(speed).build();
- nc = ncBuilder.
- addAugmentation(FlowCapableNodeConnector.class, fcnc).
- build();
- vport = InventoryUtils.toVtnPortBuilder(nc).build();
+ vport = InventoryUtils.toVtnPortBuilder(ncid, fcnc).build();
assertEquals(ncid, vport.getId());
assertEquals(key, vport.getKey());
assertEquals(name, vport.getName());
for (long dpid = 1L; dpid <= 10L; dpid++) {
for (long port = 1L; port <= 10L; port++) {
String pid = "openflow:" + dpid + ":" + port;
- NodeConnectorId ncid = new NodeConnectorId(pid);
- NodeConnectorBuilder ncBuilder = new NodeConnectorBuilder().
- setId(ncid);
- NodeConnector nc = ncBuilder.build();
+ FlowCapableNodeConnector fcnc = null;
assertEquals(VtnOpenflowVersion.OF10,
- InventoryUtils.getOpenflowVersion(nc));
+ InventoryUtils.getOpenflowVersion(fcnc));
FlowCapableNodeConnectorBuilder fcb =
new FlowCapableNodeConnectorBuilder();
- FlowCapableNodeConnector fcnc = fcb.build();
- nc = ncBuilder.
- addAugmentation(FlowCapableNodeConnector.class, fcnc).
- build();
+ fcnc = fcb.build();
assertEquals(VtnOpenflowVersion.OF10,
- InventoryUtils.getOpenflowVersion(nc));
+ InventoryUtils.getOpenflowVersion(fcnc));
fcnc = fcb.setCurrentSpeed(100000L).build();
- nc = ncBuilder.
- addAugmentation(FlowCapableNodeConnector.class, fcnc).
- build();
assertEquals(VtnOpenflowVersion.OF13,
- InventoryUtils.getOpenflowVersion(nc));
+ InventoryUtils.getOpenflowVersion(fcnc));
}
}
}
build();
assertEquals(spd1t, InventoryUtils.getLinkSpeed(pf));
}
+
+ /**
+ * Test case for the following methods.
+ *
+ * <ul>
+ * <li>{@link InventoryUtils#getNodeId(InstanceIdentifier)}</li>
+ * <li>{@link InventoryUtils#getNodeConnectorId(InstanceIdentifier)}</li>
+ * <li>{@link InventoryUtils#getLinkId(InstanceIdentifier)}</li>
+ * </ul>
+ */
+ @Test
+ public void testGetKey() {
+ TopologyKey topoKey = new TopologyKey(new TopologyId(TOPOLOGY_ID));
+ for (long dpid = 1L; dpid <= 5L; dpid++) {
+ String nid = "openflow:" + dpid;
+ NodeId nodeId = new NodeId(nid);
+ NodeKey nodeKey = new NodeKey(nodeId);
+ InstanceIdentifier<Node> path = InstanceIdentifier.
+ builder(Nodes.class).
+ child(Node.class, nodeKey).build();
+ assertEquals(nodeId, InventoryUtils.getNodeId(path));
+ assertEquals(null, InventoryUtils.getNodeConnectorId(path));
+ assertEquals(null, InventoryUtils.getLinkId(path));
+
+ for (long port = 1L; port <= 5L; port++) {
+ String pid = nid + ";" + port;
+ NodeConnectorId ncId = new NodeConnectorId(pid);
+ NodeConnectorKey ncKey = new NodeConnectorKey(ncId);
+ InstanceIdentifier<NodeConnector> ncPath = InstanceIdentifier.
+ builder(Nodes.class).
+ child(Node.class, nodeKey).
+ child(NodeConnector.class, ncKey).build();
+ assertEquals(nodeId, InventoryUtils.getNodeId(ncPath));
+ assertEquals(ncId, InventoryUtils.getNodeConnectorId(ncPath));
+ assertEquals(null, InventoryUtils.getLinkId(ncPath));
+
+ LinkId lid = new LinkId(pid);
+ LinkKey lkey = new LinkKey(lid);
+ InstanceIdentifier<Link> lpath = InstanceIdentifier.
+ builder(NetworkTopology.class).
+ child(Topology.class, topoKey).
+ child(Link.class, lkey).build();
+ assertEquals(null, InventoryUtils.getNodeId(lpath));
+ assertEquals(null, InventoryUtils.getNodeConnectorId(lpath));
+ assertEquals(lid, InventoryUtils.getLinkId(lpath));
+ }
+ }
+ }
+
+ /**
+ * Test case for the following methods.
+ *
+ * <ul>
+ * <li>{@link InventoryUtils#addVtnLink(ReadWriteTransaction,InventoryReader,LinkId,SalPort,SalPort)}</li>
+ * <li>{@link InventoryUtils#createVtnLink(ReadWriteTransaction,LinkId,SalPort,SalPort)}</li>
+ * </ul>
+ *
+ * @throws Exception An error occurred.
+ */
+ @Test
+ public void testAddVtnLink() throws Exception {
+ ReadWriteTransaction tx = Mockito.mock(ReadWriteTransaction.class);
+ InventoryReader reader = new InventoryReader(tx);
+ LogicalDatastoreType oper = LogicalDatastoreType.OPERATIONAL;
+ SalPort src = new SalPort(1L, 2L);
+ SalPort dst = new SalPort(10L, 20L);
+ LinkId lid = new LinkId(src.toString());
+ InstanceIdentifier<IgnoredLink> ipath = InstanceIdentifier.
+ builder(IgnoredLinks.class).
+ child(IgnoredLink.class, new IgnoredLinkKey(lid)).build();
+ IgnoredLink ignored = new IgnoredLinkBuilder().
+ setLinkId(lid).setSource(src.getNodeConnectorId()).
+ setDestination(dst.getNodeConnectorId()).build();
+ InstanceIdentifier<VtnLink> vpath = InstanceIdentifier.
+ builder(VtnTopology.class).
+ child(VtnLink.class, new VtnLinkKey(lid)).build();
+ VtnLink vlink = new VtnLinkBuilder().
+ setLinkId(lid).setSource(src.getNodeConnectorId()).
+ setDestination(dst.getNodeConnectorId()).build();
+ InstanceIdentifier<PortLink> srcPath = InstanceIdentifier.
+ builder(VtnNodes.class).
+ child(VtnNode.class, src.getVtnNodeKey()).
+ child(VtnPort.class, src.getVtnPortKey()).
+ child(PortLink.class, new PortLinkKey(lid)).build();
+ PortLink srcLink = new PortLinkBuilder().
+ setLinkId(lid).setPeer(dst.getNodeConnectorId()).build();
+ InstanceIdentifier<PortLink> dstPath = InstanceIdentifier.
+ builder(VtnNodes.class).
+ child(VtnNode.class, dst.getVtnNodeKey()).
+ child(VtnPort.class, dst.getVtnPortKey()).
+ child(PortLink.class, new PortLinkKey(lid)).build();
+ PortLink dstLink = new PortLinkBuilder().
+ setLinkId(lid).setPeer(src.getNodeConnectorId()).build();
+
+ // Both source and destination ports are not present.
+ reader.prefetch(src, (VtnPort)null);
+ reader.prefetch(dst, (VtnPort)null);
+ assertEquals(false,
+ InventoryUtils.addVtnLink(tx, reader, lid, src, dst));
+ Mockito.verify(tx).merge(oper, ipath, ignored, true);
+ Mockito.verify(tx, Mockito.never()).
+ merge(Mockito.eq(oper), Mockito.eq(vpath), Mockito.eq(vlink),
+ Mockito.anyBoolean());
+ Mockito.verify(tx, Mockito.never()).
+ merge(Mockito.eq(oper), Mockito.eq(srcPath), Mockito.eq(srcLink),
+ Mockito.anyBoolean());
+ Mockito.verify(tx, Mockito.never()).
+ merge(Mockito.eq(oper), Mockito.eq(dstPath), Mockito.eq(dstLink),
+ Mockito.anyBoolean());
+ Mockito.reset(tx);
+
+ // Source port is not present.
+ VtnPort dstPort = new VtnPortBuilder().setId(dst.getNodeConnectorId()).
+ build();
+ reader.prefetch(dst, dstPort);
+ assertEquals(false,
+ InventoryUtils.addVtnLink(tx, reader, lid, src, dst));
+ Mockito.verify(tx).merge(oper, ipath, ignored, true);
+ Mockito.verify(tx, Mockito.never()).
+ merge(Mockito.eq(oper), Mockito.eq(vpath), Mockito.eq(vlink),
+ Mockito.anyBoolean());
+ Mockito.verify(tx, Mockito.never()).
+ merge(Mockito.eq(oper), Mockito.eq(srcPath), Mockito.eq(srcLink),
+ Mockito.anyBoolean());
+ Mockito.verify(tx, Mockito.never()).
+ merge(Mockito.eq(oper), Mockito.eq(dstPath), Mockito.eq(dstLink),
+ Mockito.anyBoolean());
+ Mockito.reset(tx);
+
+ // Destination port is not present.
+ VtnPort srcPort = new VtnPortBuilder().setId(src.getNodeConnectorId()).
+ build();
+ reader.prefetch(src, srcPort);
+ reader.prefetch(dst, (VtnPort)null);
+ assertEquals(false,
+ InventoryUtils.addVtnLink(tx, reader, lid, src, dst));
+ Mockito.verify(tx).merge(oper, ipath, ignored, true);
+ Mockito.verify(tx, Mockito.never()).
+ merge(Mockito.eq(oper), Mockito.eq(vpath), Mockito.eq(vlink),
+ Mockito.anyBoolean());
+ Mockito.verify(tx, Mockito.never()).
+ merge(Mockito.eq(oper), Mockito.eq(srcPath), Mockito.eq(srcLink),
+ Mockito.anyBoolean());
+ Mockito.verify(tx, Mockito.never()).
+ merge(Mockito.eq(oper), Mockito.eq(dstPath), Mockito.eq(dstLink),
+ Mockito.anyBoolean());
+ Mockito.reset(tx);
+
+ // Both ports are present.
+ reader.prefetch(dst, dstPort);
+ assertEquals(true,
+ InventoryUtils.addVtnLink(tx, reader, lid, src, dst));
+ Mockito.verify(tx, Mockito.never()).
+ merge(Mockito.eq(oper), Mockito.eq(ipath), Mockito.eq(ignored),
+ Mockito.anyBoolean());
+ Mockito.verify(tx).merge(oper, vpath, vlink, true);
+ Mockito.verify(tx).merge(oper, srcPath, srcLink, true);
+ Mockito.verify(tx).merge(oper, dstPath, dstLink, true);
+ }
+
+ /**
+ * VTN topology for test.
+ */
+ private final class TopologyLists {
+ /**
+ * A list of {@link VtnLink} instances.
+ */
+ private final List<VtnLink> vtnLinks = new ArrayList<>();
+
+ /**
+ * A list of {@link IgnoredLink} instances.
+ */
+ private final List<IgnoredLink> ignoredLinks = new ArrayList<>();
+
+ /**
+ * A map that keeps paths to {@link VtnLink} instances.
+ *
+ * <p>
+ * {@link Boolean.TRUE} means the VTN link to be removed.
+ * </p>
+ */
+ private Map<InstanceIdentifier<VtnLink>, Boolean> vtnLinkPaths;
+
+ /**
+ * A map that keeps paths to {@link PortLink} intances.
+ *
+ * <p>
+ * {@link Boolean.TRUE} means the port link to be removed.
+ * </p>
+ */
+ private Map<InstanceIdentifier<PortLink>, Boolean> portLinkPaths;
+
+ /**
+ * A map that keeps paths to {@link IgnoredLink} instances.
+ *
+ * <p>
+ * {@link Boolean.TRUE} means the ignored link to be removed.
+ * </p>
+ */
+ private Map<InstanceIdentifier<IgnoredLink>, Boolean> ignoredLinkPaths;
+
+ /**
+ * Return a list of {@link VtnLink} instances.
+ *
+ * @return A list of {@link VtnLink} instances.
+ */
+ private List<VtnLink> getVtnLinks() {
+ return vtnLinks;
+ }
+
+ /**
+ * Return a list of {@link IgnoredLink} instances.
+ *
+ * @return A list of {@link IgnoredLink} instances.
+ */
+ private List<IgnoredLink> getIgnoredLinks() {
+ return ignoredLinks;
+ }
+
+ /**
+ * Add a {@link VtnLink} instance.
+ *
+ * @param src The source port.
+ * @param dst The destination port.
+ */
+ private void addVtnLink(SalPort src, SalPort dst) {
+ LinkId lid = new LinkId(src.toString());
+ VtnLink vlink = new VtnLinkBuilder().
+ setLinkId(lid).setSource(src.getNodeConnectorId()).
+ setDestination(dst.getNodeConnectorId()).build();
+ vtnLinks.add(vlink);
+ }
+
+ /**
+ * Add an {@link IgnoredLink} instance.
+ *
+ * @param src The source port.
+ * @param dst The destination port.
+ */
+ private void addIgnoredLink(SalPort src, SalPort dst) {
+ LinkId lid = new LinkId(src.toString());
+ IgnoredLink ilink = new IgnoredLinkBuilder().
+ setLinkId(lid).setSource(src.getNodeConnectorId()).
+ setDestination(dst.getNodeConnectorId()).build();
+ ignoredLinks.add(ilink);
+ }
+
+ /**
+ * Set up the mock-up of MD-SAL datastore transaction.
+ *
+ * @param tx A mock-up of {@link ReadWriteTransaction}.
+ * @param snode A {@link SalNode} to be removed.
+ */
+ private void setUp(ReadWriteTransaction tx, SalNode snode) {
+ Map<InstanceIdentifier<PortLink>, Boolean> plinks =
+ new HashMap<>();
+ Map<InstanceIdentifier<VtnLink>, Boolean> rmLinks =
+ new HashMap<>();
+ LogicalDatastoreType oper = LogicalDatastoreType.OPERATIONAL;
+ long dpid = snode.getNodeNumber();
+ for (VtnLink vlink: vtnLinks) {
+ SalPort src = SalPort.create(vlink.getSource());
+ SalPort dst = SalPort.create(vlink.getDestination());
+ LinkId lid = vlink.getLinkId();
+ boolean rmLink = false;
+ boolean rmSrc = false;
+ boolean rmDst = false;
+ if (src.getNodeNumber() == dpid) {
+ rmLink = true;
+ if (dst.getNodeNumber() != dpid) {
+ rmDst = true;
+ }
+ } else if (dst.getNodeNumber() == dpid) {
+ rmLink = true;
+ rmSrc = true;
+ }
+
+ InstanceIdentifier<VtnLink> vpath = InstanceIdentifier.
+ builder(VtnTopology.class).
+ child(VtnLink.class, new VtnLinkKey(lid)).build();
+ assertEquals(null, rmLinks.put(vpath, rmLink));
+
+ InstanceIdentifier<PortLink> ppath = InstanceIdentifier.
+ builder(VtnNodes.class).
+ child(VtnNode.class, src.getVtnNodeKey()).
+ child(VtnPort.class, src.getVtnPortKey()).
+ child(PortLink.class, new PortLinkKey(lid)).build();
+ assertEquals(null, plinks.put(ppath, rmSrc));
+ if (rmSrc) {
+ PortLink plink = new PortLinkBuilder().
+ setLinkId(lid).setPeer(dst.getNodeConnectorId()).
+ build();
+ Mockito.when(tx.read(oper, ppath)).
+ thenReturn(getReadResult(plink));
+ }
+
+ ppath = InstanceIdentifier.builder(VtnNodes.class).
+ child(VtnNode.class, dst.getVtnNodeKey()).
+ child(VtnPort.class, dst.getVtnPortKey()).
+ child(PortLink.class, new PortLinkKey(lid)).build();
+ assertEquals(null, plinks.put(ppath, rmDst));
+ if (rmDst) {
+ PortLink plink = new PortLinkBuilder().
+ setLinkId(lid).setPeer(src.getNodeConnectorId()).
+ build();
+ Mockito.when(tx.read(oper, ppath)).
+ thenReturn(getReadResult(plink));
+ }
+ }
+
+ InstanceIdentifier<VtnTopology> rpath =
+ InstanceIdentifier.create(VtnTopology.class);
+ VtnTopology root = new VtnTopologyBuilder().
+ setVtnLink(vtnLinks).build();
+ Mockito.when(tx.read(oper, rpath)).thenReturn(getReadResult(root));
+
+ vtnLinkPaths = rmLinks;
+ portLinkPaths = plinks;
+
+ Map<InstanceIdentifier<IgnoredLink>, Boolean> ilinks =
+ new HashMap<>();
+ for (IgnoredLink ilink: ignoredLinks) {
+ SalPort src = SalPort.create(ilink.getSource());
+ SalPort dst = SalPort.create(ilink.getDestination());
+ LinkId lid = ilink.getLinkId();
+ boolean rmLink = (src.getNodeNumber() == dpid ||
+ dst.getNodeNumber() == dpid);
+ InstanceIdentifier<IgnoredLink> ipath = InstanceIdentifier.
+ builder(IgnoredLinks.class).
+ child(IgnoredLink.class, new IgnoredLinkKey(lid)).build();
+ assertEquals(null, ilinks.put(ipath, rmLink));
+ }
+
+ InstanceIdentifier<IgnoredLinks> irpath =
+ InstanceIdentifier.create(IgnoredLinks.class);
+ IgnoredLinks iroot = new IgnoredLinksBuilder().
+ setIgnoredLink(ignoredLinks).build();
+ Mockito.when(tx.read(oper, irpath)).
+ thenReturn(getReadResult(iroot));
+
+ ignoredLinkPaths = ilinks;
+ }
+
+ /**
+ * Verify results of
+ * {@link InventoryUtils#removeVtnTopologyLink(ReadWriteTransaction,SalNode)}.
+ *
+ * @param tx A mock-up of {@link ReadWriteTransaction}.
+ * @param invoked {@code true} means that the method was invoked.
+ */
+ private void verifyVtnLink(ReadWriteTransaction tx, boolean invoked) {
+ LogicalDatastoreType oper = LogicalDatastoreType.OPERATIONAL;
+ InstanceIdentifier<VtnTopology> rpath =
+ InstanceIdentifier.create(VtnTopology.class);
+ if (invoked) {
+ Mockito.verify(tx).read(oper, rpath);
+ } else {
+ Mockito.verify(tx, Mockito.never()).read(oper, rpath);
+ }
+
+ for (Map.Entry<InstanceIdentifier<VtnLink>, Boolean> entry:
+ vtnLinkPaths.entrySet()) {
+ InstanceIdentifier<VtnLink> vpath = entry.getKey();
+ Mockito.verify(tx, Mockito.never()).read(oper, vpath);
+
+ Boolean removed = entry.getValue();
+ if (invoked && Boolean.TRUE.equals(removed)) {
+ Mockito.verify(tx).delete(oper, vpath);
+ } else {
+ Mockito.verify(tx, Mockito.never()).delete(oper, vpath);
+ }
+ }
+
+ for (Map.Entry<InstanceIdentifier<PortLink>, Boolean> entry:
+ portLinkPaths.entrySet()) {
+ InstanceIdentifier<PortLink> ppath = entry.getKey();
+ Boolean removed = entry.getValue();
+ if (invoked && Boolean.TRUE.equals(removed)) {
+ Mockito.verify(tx).read(oper, ppath);
+ Mockito.verify(tx).delete(oper, ppath);
+ } else {
+ Mockito.verify(tx, Mockito.never()).read(oper, ppath);
+ Mockito.verify(tx, Mockito.never()).delete(oper, ppath);
+ }
+ }
+ }
+
+ /**
+ * Verify results of
+ * {@link InventoryUtils#removeIgnoredLink(ReadWriteTransaction,SalNode)}.
+ *
+ * @param tx A mock-up of {@link ReadWriteTransaction}.
+ * @param invoked {@code true} means that the method was invoked.
+ */
+ private void verifyIgnoredLink(ReadWriteTransaction tx,
+ boolean invoked) {
+ LogicalDatastoreType oper = LogicalDatastoreType.OPERATIONAL;
+ InstanceIdentifier<IgnoredLinks> irpath =
+ InstanceIdentifier.create(IgnoredLinks.class);
+ if (invoked) {
+ Mockito.verify(tx).read(oper, irpath);
+ } else {
+ Mockito.verify(tx, Mockito.never()).read(oper, irpath);
+ }
+
+ for (Map.Entry<InstanceIdentifier<IgnoredLink>, Boolean> entry:
+ ignoredLinkPaths.entrySet()) {
+ InstanceIdentifier<IgnoredLink> ipath = entry.getKey();
+ Mockito.verify(tx, Mockito.never()).read(oper, ipath);
+
+ Boolean removed = entry.getValue();
+ if (invoked && Boolean.TRUE.equals(removed)) {
+ Mockito.verify(tx).delete(oper, ipath);
+ } else {
+ Mockito.verify(tx, Mockito.never()).delete(oper, ipath);
+ }
+ }
+ }
+ }
+
+ /**
+ * Generator of {@link SalPort} instances.
+ */
+ private static final class SalPortGenerator {
+ /**
+ * Node number.
+ */
+ private final long nodeNumber;
+
+ /**
+ * Port number.
+ */
+ private long portNumber;
+
+ /**
+ * Construct a new instance.
+ *
+ * @param dpid A node number.
+ */
+ private SalPortGenerator(long dpid) {
+ nodeNumber = dpid;
+ }
+
+ /**
+ * Construct a new {@link SalPort} instance.
+ *
+ * @return A {@link SalPort} instance.
+ */
+ private SalPort newInstance() {
+ return new SalPort(nodeNumber, ++portNumber);
+ }
+ }
+
+ /**
+ * Test case for the following methods.
+ *
+ * <ul>
+ * <li>{@link InventoryUtils#removeVtnLink(ReadWriteTransaction,SalNode)}</li>
+ * <li>{@link InventoryUtils#removeVtnTopologyLink(ReadWriteTransaction,SalNode)}</li>
+ * <li>{@link InventoryUtils#removeIgnoredLink(ReadWriteTransaction,SalNode)}</li>
+ * </ul>
+ *
+ * @throws Exception An error occurred.
+ */
+ @Test
+ public void testRemoveVtnLinkByNode() throws Exception {
+ ReadWriteTransaction tx = Mockito.mock(ReadWriteTransaction.class);
+ LogicalDatastoreType oper = LogicalDatastoreType.OPERATIONAL;
+
+ // Root containers are not present.
+ long dpid = 10L;
+ SalNode snode = new SalNode(dpid);
+ InstanceIdentifier<VtnTopology> rpath =
+ InstanceIdentifier.create(VtnTopology.class);
+ InstanceIdentifier<IgnoredLinks> irpath =
+ InstanceIdentifier.create(IgnoredLinks.class);
+ VtnTopology root = null;
+ IgnoredLinks iroot = null;
+ Mockito.when(tx.read(oper, rpath)).thenReturn(getReadResult(root));
+ Mockito.when(tx.read(oper, irpath)).thenReturn(getReadResult(iroot));
+ InventoryUtils.removeVtnLink(tx, snode);
+ Mockito.verify(tx).read(oper, rpath);
+ Mockito.verify(tx).read(oper, irpath);
+
+ InventoryUtils.removeVtnTopologyLink(tx, snode);
+ Mockito.verify(tx, Mockito.times(2)).read(oper, rpath);
+ Mockito.verify(tx).read(oper, irpath);
+
+ InventoryUtils.removeIgnoredLink(tx, snode);
+ Mockito.verify(tx, Mockito.times(2)).read(oper, rpath);
+ Mockito.verify(tx, Mockito.times(2)).read(oper, irpath);
+ Mockito.reset(tx);
+
+ // Root containers contain null list.
+ root = new VtnTopologyBuilder().build();
+ iroot = new IgnoredLinksBuilder().build();
+ Mockito.when(tx.read(oper, rpath)).thenReturn(getReadResult(root));
+ Mockito.when(tx.read(oper, irpath)).thenReturn(getReadResult(iroot));
+ InventoryUtils.removeVtnLink(tx, snode);
+ Mockito.verify(tx).read(oper, rpath);
+ Mockito.verify(tx).read(oper, irpath);
+
+ InventoryUtils.removeVtnTopologyLink(tx, snode);
+ Mockito.verify(tx, Mockito.times(2)).read(oper, rpath);
+ Mockito.verify(tx).read(oper, irpath);
+
+ InventoryUtils.removeIgnoredLink(tx, snode);
+ Mockito.verify(tx, Mockito.times(2)).read(oper, rpath);
+ Mockito.verify(tx, Mockito.times(2)).read(oper, irpath);
+ Mockito.reset(tx);
+
+ // Root containers contain empty list.
+ List<VtnLink> vlinks = new ArrayList<>();
+ List<IgnoredLink> ilinks = new ArrayList<>();
+ root = new VtnTopologyBuilder().setVtnLink(vlinks).build();
+ iroot = new IgnoredLinksBuilder().setIgnoredLink(ilinks).build();
+ Mockito.when(tx.read(oper, rpath)).thenReturn(getReadResult(root));
+ Mockito.when(tx.read(oper, irpath)).thenReturn(getReadResult(iroot));
+ InventoryUtils.removeVtnLink(tx, snode);
+ Mockito.verify(tx).read(oper, rpath);
+ Mockito.verify(tx).read(oper, irpath);
+
+ InventoryUtils.removeVtnTopologyLink(tx, snode);
+ Mockito.verify(tx, Mockito.times(2)).read(oper, rpath);
+ Mockito.verify(tx).read(oper, irpath);
+
+ InventoryUtils.removeIgnoredLink(tx, snode);
+ Mockito.verify(tx, Mockito.times(2)).read(oper, rpath);
+ Mockito.verify(tx, Mockito.times(2)).read(oper, irpath);
+ Mockito.reset(tx);
+
+ SalPortGenerator gen = new SalPortGenerator(dpid);
+ SalPortGenerator gen1 = new SalPortGenerator(dpid + 1L);
+ SalPortGenerator gen2 = new SalPortGenerator(dpid + 2L);
+ SalPortGenerator[] peers = {
+ gen1, gen2,
+ };
+ TopologyLists topo = new TopologyLists();
+ for (int i = 0; i < 5; i++) {
+ SalPort src = gen.newInstance();
+ SalPort dst = gen.newInstance();
+ topo.addVtnLink(src, dst);
+
+ src = gen.newInstance();
+ dst = gen.newInstance();
+ topo.addIgnoredLink(src, dst);
+
+ for (SalPortGenerator pgen: peers) {
+ src = gen.newInstance();
+ dst = pgen.newInstance();
+ topo.addVtnLink(src, dst);
+
+ src = gen.newInstance();
+ dst = pgen.newInstance();
+ topo.addIgnoredLink(src, dst);
+
+ src = pgen.newInstance();
+ dst = gen.newInstance();
+ topo.addVtnLink(src, dst);
+
+ src = pgen.newInstance();
+ dst = gen.newInstance();
+ topo.addIgnoredLink(src, dst);
+ }
+
+ src = gen1.newInstance();
+ dst = gen2.newInstance();
+ topo.addVtnLink(src, dst);
+
+ src = gen1.newInstance();
+ dst = gen2.newInstance();
+ topo.addIgnoredLink(src, dst);
+
+ src = gen2.newInstance();
+ dst = gen1.newInstance();
+ topo.addVtnLink(src, dst);
+
+ src = gen2.newInstance();
+ dst = gen1.newInstance();
+ topo.addIgnoredLink(src, dst);
+ }
+
+ topo.setUp(tx, snode);
+ InventoryUtils.removeVtnLink(tx, snode);
+ topo.verifyVtnLink(tx, true);
+ topo.verifyIgnoredLink(tx, true);
+ Mockito.reset(tx);
+
+ topo.setUp(tx, snode);
+ InventoryUtils.removeVtnTopologyLink(tx, snode);
+ topo.verifyVtnLink(tx, true);
+ topo.verifyIgnoredLink(tx, false);
+ Mockito.reset(tx);
+
+ topo.setUp(tx, snode);
+ InventoryUtils.removeIgnoredLink(tx, snode);
+ topo.verifyVtnLink(tx, false);
+ topo.verifyIgnoredLink(tx, true);
+ Mockito.reset(tx);
+ }
+
+ /**
+ * Test case for the following methods.
+ *
+ * <ul>
+ * <li>{@link InventoryUtils#removeVtnLink(ReadWriteTransaction,VtnPort)}</li>
+ * <li>{@link InventoryUtils#removePortLink(ReadWriteTransaction,SalPort,LinkId)}</li>
+ * </ul>
+ *
+ * @throws Exception An error occurred.
+ */
+ @Test
+ public void testRemoveVtnLinkByPort() throws Exception {
+ ReadWriteTransaction tx = Mockito.mock(ReadWriteTransaction.class);
+ LogicalDatastoreType oper = LogicalDatastoreType.OPERATIONAL;
+
+ // Port link is null.
+ VtnPort vport = new VtnPortBuilder().build();
+ InventoryUtils.removeVtnLink(tx, vport);
+ Mockito.verifyZeroInteractions(tx);
+
+ // Port link is empty.
+ List<PortLink> plist = new ArrayList<>();
+ vport = new VtnPortBuilder().setPortLink(plist).build();
+ InventoryUtils.removeVtnLink(tx, vport);
+ Mockito.verifyZeroInteractions(tx);
+
+ Map<InstanceIdentifier<VtnLink>, VtnLink> vtnLinks = new HashMap<>();
+ Map<InstanceIdentifier<PortLink>, PortLink> peerLinks =
+ new HashMap<>();
+ Set<InstanceIdentifier<PortLink>> portLinks = new HashSet<>();
+ long dpid = 10L;
+ final SalPort sport = new SalPort(dpid, 3L);
+ final SalPort peer = new SalPort(dpid + 10L, 1L);
+
+ LinkId lid1 = new LinkId(sport.toString());
+ InstanceIdentifier<PortLink> portPath1 = InstanceIdentifier.
+ builder(VtnNodes.class).
+ child(VtnNode.class, sport.getVtnNodeKey()).
+ child(VtnPort.class, sport.getVtnPortKey()).
+ child(PortLink.class, new PortLinkKey(lid1)).build();
+ PortLink portLink1 = new PortLinkBuilder().
+ setLinkId(lid1).setPeer(peer.getNodeConnectorId()).build();
+ InstanceIdentifier<PortLink> peerPath1 = InstanceIdentifier.
+ builder(VtnNodes.class).
+ child(VtnNode.class, peer.getVtnNodeKey()).
+ child(VtnPort.class, peer.getVtnPortKey()).
+ child(PortLink.class, new PortLinkKey(lid1)).build();
+ InstanceIdentifier<VtnLink> vpath1 = InstanceIdentifier.
+ builder(VtnTopology.class).
+ child(VtnLink.class, new VtnLinkKey(lid1)).build();
+
+ LinkId lid2 = new LinkId(peer.toString());
+ InstanceIdentifier<PortLink> portPath2 = InstanceIdentifier.
+ builder(VtnNodes.class).
+ child(VtnNode.class, sport.getVtnNodeKey()).
+ child(VtnPort.class, sport.getVtnPortKey()).
+ child(PortLink.class, new PortLinkKey(lid2)).build();
+ PortLink portLink2 = new PortLinkBuilder().
+ setLinkId(lid2).setPeer(peer.getNodeConnectorId()).build();
+ InstanceIdentifier<PortLink> peerPath2 = InstanceIdentifier.
+ builder(VtnNodes.class).
+ child(VtnNode.class, peer.getVtnNodeKey()).
+ child(VtnPort.class, peer.getVtnPortKey()).
+ child(PortLink.class, new PortLinkKey(lid2)).build();
+ InstanceIdentifier<VtnLink> vpath2 = InstanceIdentifier.
+ builder(VtnTopology.class).
+ child(VtnLink.class, new VtnLinkKey(lid2)).build();
+ List<PortLink> plinks = new ArrayList<>();
+ Collections.addAll(plinks, portLink1, portLink2);
+ vport = new VtnPortBuilder().setId(sport.getNodeConnectorId()).
+ setPortLink(plinks).build();
+
+ // No link information is present.
+ Mockito.when(tx.read(oper, peerPath1)).
+ thenReturn(getReadResult((PortLink)null));
+ Mockito.when(tx.read(oper, peerPath2)).
+ thenReturn(getReadResult((PortLink)null));
+ Mockito.when(tx.read(oper, vpath1)).
+ thenReturn(getReadResult((VtnLink)null));
+ Mockito.when(tx.read(oper, vpath2)).
+ thenReturn(getReadResult((VtnLink)null));
+
+ InventoryUtils.removeVtnLink(tx, vport);
+ Mockito.verify(tx).read(oper, peerPath1);
+ Mockito.verify(tx).read(oper, peerPath2);
+ Mockito.verify(tx).read(oper, vpath1);
+ Mockito.verify(tx).read(oper, vpath2);
+ Mockito.verify(tx, Mockito.never()).delete(oper, peerPath1);
+ Mockito.verify(tx, Mockito.never()).delete(oper, peerPath2);
+ Mockito.verify(tx, Mockito.never()).delete(oper, vpath1);
+ Mockito.verify(tx, Mockito.never()).delete(oper, vpath2);
+ Mockito.reset(tx);
+
+ // Link information is present.
+ PortLink peerLink1 = new PortLinkBuilder().
+ setLinkId(lid1).setPeer(sport.getNodeConnectorId()).build();
+ PortLink peerLink2 = new PortLinkBuilder().
+ setLinkId(lid2).setPeer(sport.getNodeConnectorId()).build();
+ VtnLink vlink1 = new VtnLinkBuilder().
+ setLinkId(lid1).setSource(sport.getNodeConnectorId()).
+ setDestination(peer.getNodeConnectorId()).build();
+ VtnLink vlink2 = new VtnLinkBuilder().
+ setLinkId(lid2).setSource(peer.getNodeConnectorId()).
+ setDestination(sport.getNodeConnectorId()).build();
+ Mockito.when(tx.read(oper, peerPath1)).
+ thenReturn(getReadResult(peerLink1));
+ Mockito.when(tx.read(oper, peerPath2)).
+ thenReturn(getReadResult(peerLink2));
+ Mockito.when(tx.read(oper, vpath1)).thenReturn(getReadResult(vlink1));
+ Mockito.when(tx.read(oper, vpath2)).thenReturn(getReadResult(vlink2));
+
+ InventoryUtils.removeVtnLink(tx, vport);
+ Mockito.verify(tx).read(oper, peerPath1);
+ Mockito.verify(tx).read(oper, peerPath2);
+ Mockito.verify(tx).read(oper, vpath1);
+ Mockito.verify(tx).read(oper, vpath2);
+ Mockito.verify(tx).delete(oper, peerPath1);
+ Mockito.verify(tx).delete(oper, peerPath2);
+ Mockito.verify(tx).delete(oper, vpath1);
+ Mockito.verify(tx).delete(oper, vpath2);
+ }
+
+ /**
+ * Test environment for {@link #testResolveIgnoredLinks()}.
+ */
+ private final class ResolveLinkEnv {
+ /**
+ * The mock-up of MD-SAL datastore transaction.
+ */
+ private final ReadWriteTransaction transaction =
+ Mockito.mock(ReadWriteTransaction.class);
+
+ /**
+ * The mock-up of logger instance.
+ */
+ private final Logger logger = Mockito.mock(Logger.class);
+
+ /**
+ * Inventory reader.
+ */
+ private final InventoryReader reader =
+ new InventoryReader(transaction);
+
+ /**
+ * A list of {@link IgnoredLink} instances.
+ */
+ private final List<IgnoredLink> ignoredLinks = new ArrayList<>();
+
+ /**
+ * VTN ignored links to be removed.
+ */
+ private final Set<InstanceIdentifier<IgnoredLink>> removedLinks =
+ new HashSet<>();
+
+ /**
+ * VTN links to be created.
+ */
+ private final Map<InstanceIdentifier<VtnLink>, VtnLink> vtnLinks =
+ new HashMap<>();
+
+ /**
+ * VTN port links to be created.
+ */
+ private final Map<InstanceIdentifier<PortLink>, PortLink> portLinks =
+ new HashMap<>();
+
+ /**
+ * Return the mock-up of MD-SAL transaction.
+ *
+ * @return A {@link ReadWriteTransaction} instance.
+ */
+ private ReadWriteTransaction getTransaction() {
+ return transaction;
+ }
+
+ /**
+ * Return the mock-up of logger instance.
+ *
+ * @return A {@link Logger} instance.
+ */
+ private Logger getLogger() {
+ return logger;
+ }
+
+ /**
+ * Return the inventory reader for test.
+ *
+ * @return An {@link InventoryReader} instance.
+ */
+ private InventoryReader getInventoryReader() {
+ return reader;
+ }
+
+ /**
+ * Add the given link information.
+ *
+ * @param src The source port.
+ * @param srcPresent {@code true} means that the source port is
+ * present.
+ * @param dst The destination port.
+ * @param dstPresent {@code true} means that the destination port is
+ * present.
+ */
+ private void add(SalPort src, boolean srcPresent, SalPort dst,
+ boolean dstPresent) {
+ LinkId lid = new LinkId(src.toString());
+ IgnoredLink ilink = new IgnoredLinkBuilder().
+ setLinkId(lid).setSource(src.getNodeConnectorId()).
+ setDestination(dst.getNodeConnectorId()).build();
+ ignoredLinks.add(ilink);
+
+ VtnPort vport;
+ if (srcPresent) {
+ vport = new VtnPortBuilder().
+ setId(src.getNodeConnectorId()).build();
+ } else {
+ vport = null;
+ }
+ reader.prefetch(src, vport);
+
+ if (dstPresent) {
+ vport = new VtnPortBuilder().
+ setId(dst.getNodeConnectorId()).build();
+ } else {
+ vport = null;
+ }
+ reader.prefetch(dst, vport);
+
+ InstanceIdentifier<IgnoredLink> ipath = InstanceIdentifier.
+ builder(IgnoredLinks.class).
+ child(IgnoredLink.class, new IgnoredLinkKey(lid)).build();
+ InstanceIdentifier<VtnLink> vpath = InstanceIdentifier.
+ builder(VtnTopology.class).
+ child(VtnLink.class, new VtnLinkKey(lid)).build();
+ InstanceIdentifier<PortLink> spath = InstanceIdentifier.
+ builder(VtnNodes.class).
+ child(VtnNode.class, src.getVtnNodeKey()).
+ child(VtnPort.class, src.getVtnPortKey()).
+ child(PortLink.class, new PortLinkKey(lid)).build();
+ InstanceIdentifier<PortLink> dpath = InstanceIdentifier.
+ builder(VtnNodes.class).
+ child(VtnNode.class, dst.getVtnNodeKey()).
+ child(VtnPort.class, dst.getVtnPortKey()).
+ child(PortLink.class, new PortLinkKey(lid)).build();
+ assertEquals(false, vtnLinks.containsKey(vpath));
+ assertEquals(false, portLinks.containsKey(spath));
+ assertEquals(false, portLinks.containsKey(dpath));
+
+ VtnLink vlink = null;
+ PortLink splink = null;
+ PortLink dplink = null;
+ if (srcPresent && dstPresent) {
+ assertEquals(true, removedLinks.add(ipath));
+ NodeConnectorId sncid = src.getNodeConnectorId();
+ NodeConnectorId dncid = dst.getNodeConnectorId();
+ vlink = new VtnLinkBuilder().setLinkId(lid).
+ setSource(sncid).setDestination(dncid).build();
+ splink = new PortLinkBuilder().setLinkId(lid).setPeer(dncid).
+ build();
+ dplink = new PortLinkBuilder().setLinkId(lid).setPeer(sncid).
+ build();
+ }
+
+ assertEquals(null, vtnLinks.put(vpath, vlink));
+ assertEquals(null, portLinks.put(spath, splink));
+ assertEquals(null, portLinks.put(dpath, dplink));
+ }
+
+ /**
+ * Run the test.
+ *
+ * @throws Exception An error occurred.
+ */
+ private void runTest() throws Exception {
+ ReadWriteTransaction tx = transaction;
+ LogicalDatastoreType oper = LogicalDatastoreType.OPERATIONAL;
+ InstanceIdentifier<IgnoredLinks> irpath =
+ InstanceIdentifier.create(IgnoredLinks.class);
+ IgnoredLinks iroot = new IgnoredLinksBuilder().
+ setIgnoredLink(ignoredLinks).build();
+ Mockito.when(tx.read(oper, irpath)).
+ thenReturn(getReadResult(iroot));
+ InventoryUtils.resolveIgnoredLinks(tx, reader, logger);
+
+ for (IgnoredLink ilink: ignoredLinks) {
+ LinkId lid = ilink.getLinkId();
+ InstanceIdentifier<IgnoredLink> ipath = InstanceIdentifier.
+ builder(IgnoredLinks.class).
+ child(IgnoredLink.class, new IgnoredLinkKey(lid)).build();
+ String linkId = lid.getValue();
+ SalPort src = SalPort.create(ilink.getSource());
+ SalPort dst = SalPort.create(ilink.getDestination());
+ String msg =
+ "Inter-switch link has been resolved: {}: {} -> {}";
+ if (removedLinks.contains(ipath)) {
+ Mockito.verify(tx).delete(oper, ipath);
+ Mockito.verify(logger).info(msg, linkId, src, dst);
+ } else {
+ Mockito.verify(tx, Mockito.never()).delete(oper, ipath);
+ Mockito.verify(logger, Mockito.never()).
+ info(msg, linkId, src, dst);
+ }
+ }
+
+ for (Map.Entry<InstanceIdentifier<VtnLink>, VtnLink> entry:
+ vtnLinks.entrySet()) {
+ InstanceIdentifier<VtnLink> vpath = entry.getKey();
+ VtnLink vlink = entry.getValue();
+ if (vlink == null) {
+ Mockito.verify(tx, Mockito.never()).
+ merge(Mockito.any(LogicalDatastoreType.class),
+ Mockito.eq(vpath), Mockito.any(VtnLink.class),
+ Mockito.anyBoolean());
+ } else {
+ Mockito.verify(tx).merge(oper, vpath, vlink, true);
+ }
+ }
+
+ for (Map.Entry<InstanceIdentifier<PortLink>, PortLink> entry:
+ portLinks.entrySet()) {
+ InstanceIdentifier<PortLink> ppath = entry.getKey();
+ PortLink plink = entry.getValue();
+ if (plink == null) {
+ Mockito.verify(tx, Mockito.never()).
+ merge(Mockito.any(LogicalDatastoreType.class),
+ Mockito.eq(ppath), Mockito.any(PortLink.class),
+ Mockito.anyBoolean());
+ } else {
+ Mockito.verify(tx).merge(oper, ppath, plink, true);
+ }
+ }
+ }
+ }
+
+ /**
+ * Test case for
+ * {@link InventoryUtils#resolveIgnoredLinks(ReadWriteTransaction,InventoryReader,Logger)}.
+ *
+ * @throws Exception An error occurred.
+ */
+ @Test
+ public void testResolveIgnoredLinks() throws Exception {
+ ResolveLinkEnv env = new ResolveLinkEnv();
+ ReadWriteTransaction tx = env.getTransaction();
+ Logger log = env.getLogger();
+ InventoryReader reader = env.getInventoryReader();
+ LogicalDatastoreType oper = LogicalDatastoreType.OPERATIONAL;
+
+ // Root container is not present.
+ InstanceIdentifier<IgnoredLinks> irpath =
+ InstanceIdentifier.create(IgnoredLinks.class);
+ IgnoredLinks iroot = null;
+ Mockito.when(tx.read(oper, irpath)).thenReturn(getReadResult(iroot));
+ InventoryUtils.resolveIgnoredLinks(tx, reader, log);
+ Mockito.verify(tx).read(oper, irpath);
+ Mockito.verifyZeroInteractions(log);
+ Mockito.reset(tx, log);
+
+ // Ignored link list is null.
+ iroot = new IgnoredLinksBuilder().build();
+ Mockito.when(tx.read(oper, irpath)).thenReturn(getReadResult(iroot));
+ InventoryUtils.resolveIgnoredLinks(tx, reader, log);
+ Mockito.verify(tx).read(oper, irpath);
+ Mockito.verifyZeroInteractions(log);
+ Mockito.reset(tx, log);
+
+ // Ignored link list is empty.
+ List<IgnoredLink> ilinks = new ArrayList<>();
+ iroot = new IgnoredLinksBuilder().setIgnoredLink(ilinks).build();
+ Mockito.when(tx.read(oper, irpath)).thenReturn(getReadResult(iroot));
+ InventoryUtils.resolveIgnoredLinks(tx, reader, log);
+ Mockito.verify(tx).read(oper, irpath);
+ Mockito.verifyZeroInteractions(log);
+ Mockito.reset(tx, log);
+
+ SalPortGenerator[] generators = {
+ new SalPortGenerator(10L),
+ new SalPortGenerator(11L),
+ new SalPortGenerator(20L),
+ };
+
+ for (SalPortGenerator gen1: generators) {
+ for (SalPortGenerator gen2: generators) {
+ if (gen1.equals(gen2)) {
+ continue;
+ }
+
+ // Both source and destination ports are not present.
+ SalPort src = gen1.newInstance();
+ SalPort dst = gen2.newInstance();
+ env.add(src, false, dst, false);
+
+ // Only source port is present.
+ src = gen1.newInstance();
+ dst = gen2.newInstance();
+ env.add(src, true, dst, false);
+
+ // Only destination port is present.
+ src = gen1.newInstance();
+ dst = gen2.newInstance();
+ env.add(src, false, dst, true);
+
+ // Both source and destination ports are present.
+ src = gen1.newInstance();
+ dst = gen2.newInstance();
+ env.add(src, true, dst, true);
+ }
+ }
+
+ env.runTest();
+ }
}
package org.opendaylight.vtn.manager.it.ofmock.impl;
import java.math.BigInteger;
+import java.util.Collections;
import java.util.Dictionary;
import java.util.HashSet;
import java.util.Hashtable;
import java.util.Iterator;
+import java.util.List;
import java.util.Map;
import java.util.Set;
+import java.util.Timer;
+import java.util.TimerTask;
import java.util.concurrent.atomic.AtomicReference;
import org.slf4j.Logger;
import org.osgi.framework.FrameworkUtil;
import org.osgi.framework.ServiceRegistration;
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+
import org.opendaylight.controller.connectionmanager.IConnectionManager;
import org.opendaylight.controller.sal.connection.ConnectionLocality;
+import org.opendaylight.controller.sal.core.AdvertisedBandwidth;
+import org.opendaylight.controller.sal.core.Bandwidth;
+import org.opendaylight.controller.sal.core.Buffers;
+import org.opendaylight.controller.sal.core.Capabilities;
+import org.opendaylight.controller.sal.core.Config;
+import org.opendaylight.controller.sal.core.MacAddress;
+import org.opendaylight.controller.sal.core.Name;
import org.opendaylight.controller.sal.core.Node;
import org.opendaylight.controller.sal.core.NodeConnector;
+import org.opendaylight.controller.sal.core.PeerBandwidth;
import org.opendaylight.controller.sal.core.Property;
+import org.opendaylight.controller.sal.core.SupportedBandwidth;
+import org.opendaylight.controller.sal.core.Tables;
+import org.opendaylight.controller.sal.core.TimeStamp;
import org.opendaylight.controller.sal.core.UpdateType;
import org.opendaylight.controller.sal.flowprogrammer.IPluginInFlowProgrammerService;
import org.opendaylight.controller.sal.inventory.IListenInventoryUpdates;
import org.opendaylight.controller.sal.inventory.IPluginInInventoryService;
+import org.opendaylight.controller.sal.inventory.IPluginOutInventoryService;
import org.opendaylight.controller.sal.utils.GlobalConstants;
import org.opendaylight.controller.sal.utils.NodeConnectorCreator;
import org.opendaylight.controller.sal.utils.NodeCreator;
import org.opendaylight.controller.switchmanager.IInventoryListener;
import org.opendaylight.controller.switchmanager.ISwitchManager;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FeatureCapability;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowFeatureCapabilityFlowStats;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowNode;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.flow.node.SwitchFeatures;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.port.rev130925.FlowCapablePort;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.port.rev130925.PortConfig;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.port.rev130925.PortFeatures;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.port.rev130925.flow.capable.port.State;
+
/**
* AD-SAL inventory management.
*/
-public final class AdSalInventory implements IInventoryListener {
+public final class AdSalInventory
+ implements IInventoryListener, AutoCloseable {
/**
* Logger instance.
*/
private static final Logger LOG =
LoggerFactory.getLogger(AdSalInventory.class);
+ /**
+ * The number of bytes in a MAC address.
+ */
+ private static final int MAC_ADDRESS_LENGTH = 6;
+
/**
* The number of milliseconds to wait for AD-SAL inventory to be
* synchronized.
*/
private static final long SYNC_TIMEOUT = 30000L;
+ /**
+ * The number of milliseconds to wait for sal-compatibility to update
+ * the AD-SAL inventory.
+ */
+ private static final long COMPAT_TIMEOUT = 2000L;
+
/**
* The number of milliseconds between polls.
*/
private static final long POLL_INTERVAL = 500L;
+ /**
+ * AD-SAL switch manager service.
+ */
+ private final ISwitchManager switchManager;
+
/**
* AD-SAL connection manager service.
*/
private final IConnectionManager connectionManager;
+ /**
+ * AD-SAL inventory output service.
+ */
+ private final IPluginOutInventoryService inventoryOutGlobal;
+
+ /**
+ * AD-SAL inventory output service for the default container.
+ */
+ private final IPluginOutInventoryService inventoryOut;
+
/**
* An OSGi bundle context for this OSGi bundle.
*/
private final AtomicReference<ServiceRegistration<?>> inventoryListener =
new AtomicReference<>();
+ /**
+ * A set of MD-SAL listeners.
+ */
+ private final AtomicReference<Set<DataStoreListener<?, ?>>> dataListeners =
+ new AtomicReference<>();
+
+ /**
+ * A map that keeps current AD-SAL nodes.
+ */
+ private final Map<Node, Set<Property>> adNodes = new Hashtable<>();
+
+ /**
+ * A map that keeps current AD-SAL node connectors.
+ */
+ private final Map<NodeConnector, Set<Property>> adNodeConnectors =
+ new Hashtable<>();
+
+ /**
+ * Timer thread used to maintain AD-SAL inventory.
+ */
+ private final AtomicReference<Timer> inventoryTimer =
+ new AtomicReference<>();
+
/**
* Convert the given MD-SAL node identifier into AD-SAL node.
*
"Invalid node connector identifier: " + pid);
}
+ /**
+ * Convert the given MD-SAL flow-node into a set of AD-SAL node properties.
+
+ * @param node A {@link Node} instance.
+ * @param fn A {@link FlowNode} instance.
+ * @return A set of AD-SAL node properties.
+ */
+ public static Set<Property> toProperties(Node node, FlowNode fn) {
+ Set<Property> props = new HashSet<>();
+ Object id = node.getID();
+ long dpid = (id instanceof Number) ? ((Number)id).longValue() : 0;
+ byte[] mac = new byte[MAC_ADDRESS_LENGTH];
+ for (int i = 1; i <= mac.length; i++) {
+ mac[mac.length - i] = (byte)dpid;
+ dpid >>>= Byte.SIZE;
+ }
+ props.add(new MacAddress(mac));
+ props.add(new TimeStamp(System.currentTimeMillis(), "connectedSince"));
+
+ SwitchFeatures swf = fn.getSwitchFeatures();
+ if (swf != null) {
+ Short tables = swf.getMaxTables();
+ if (tables != null) {
+ props.add(new Tables(tables.byteValue()));
+ }
+
+ Long buffers = swf.getMaxBuffers();
+ if (buffers != null) {
+ props.add(new Buffers(buffers.intValue()));
+ }
+
+ setNodeCapabilities(props, swf.getCapabilities());
+ }
+
+ return Collections.unmodifiableSet(props);
+ }
+
+ /**
+ * Convert the given MD-SAL flow-capable-port into a set of AD-SAL node
+ * connector properties.
+ *
+ * @param fcp A {@link FlowCapablePort} instance.
+ * @return A set of AD-SAL node connector properties.
+ */
+ public static Set<Property> toProperties(FlowCapablePort fcp) {
+ Set<Property> props = toBandwidthProps(fcp);
+ String name = fcp.getName();
+ if (name != null) {
+ props.add(new Name(name));
+ }
+
+ PortConfig pc = fcp.getConfiguration();
+ if (pc != null) {
+ short cfg = (pc.isPORTDOWN())
+ ? Config.ADMIN_DOWN : Config.ADMIN_UP;
+ props.add(new Config(cfg));
+ }
+
+ State state = fcp.getState();
+ if (state != null) {
+ short st = (state.isLinkDown())
+ ? org.opendaylight.controller.sal.core.State.EDGE_DOWN
+ : org.opendaylight.controller.sal.core.State.EDGE_UP;
+ props.add(new org.opendaylight.controller.sal.core.State(st));
+ }
+
+ return Collections.unmodifiableSet(props);
+ }
+
+ /**
+ * Set AD-SAL node properties from the given capability list.
+ *
+ * @param props A set of AD-SAL node properties.
+ * @param fclist A list of MD-SAL node capability classes.
+ */
+ public static void setNodeCapabilities(
+ Set<Property> props, List<Class<? extends FeatureCapability>> fclist) {
+ if (fclist != null) {
+ int bits = 0;
+ for (Class<? extends FeatureCapability> fc: fclist) {
+ if (fc.equals(FlowFeatureCapabilityFlowStats.class)) {
+ bits |= Capabilities.CapabilitiesType.
+ FLOW_STATS_CAPABILITY.getValue();
+ }
+ }
+
+ props.add(new Capabilities(bits));
+ }
+ }
+
+ /**
+ * Create AD-SAL node connector properties related to bandwidth.
+ *
+ * @param fcp A {@link FlowCapablePort} instance.
+ * @return A set of AD-SAL node connector properties.
+ */
+ public static Set<Property> toBandwidthProps(FlowCapablePort fcp) {
+ Set<Property> props = new HashSet<>();
+ PortFeatures pf = fcp.getCurrentFeature();
+ if (pf != null) {
+ long bw = toBandwidth(pf);
+ if (bw != Bandwidth.BWUNK) {
+ props.add(new Bandwidth(bw));
+ }
+ }
+
+ pf = fcp.getAdvertisedFeatures();
+ if (pf != null) {
+ long bw = toBandwidth(pf);
+ if (bw != Bandwidth.BWUNK) {
+ props.add(new AdvertisedBandwidth(bw));
+ }
+ }
+
+ pf = fcp.getSupported();
+ if (pf != null) {
+ long bw = toBandwidth(pf);
+ if (bw != Bandwidth.BWUNK) {
+ props.add(new SupportedBandwidth(bw));
+ }
+ }
+
+ pf = fcp.getPeerFeatures();
+ if (pf != null) {
+ long bw = toBandwidth(pf);
+ if (bw != Bandwidth.BWUNK) {
+ props.add(new PeerBandwidth(bw));
+ }
+ }
+
+ return props;
+ }
+
+ /**
+ * Convert the given MD-SAL port features into AD-SAL bandwidth value.
+ *
+ * @param pf A {@link PortFeatures} instance.
+ * @return An AD-SAL bandwidth value.
+ */
+ public static long toBandwidth(PortFeatures pf) {
+ if (pf.isTenMbHd() || pf.isTenMbFd()) {
+ return Bandwidth.BW10Mbps;
+ }
+ if (pf.isHundredMbHd() || pf.isHundredMbFd()) {
+ return Bandwidth.BW100Mbps;
+ }
+ if (pf.isOneGbHd() || pf.isOneGbFd()) {
+ return Bandwidth.BW1Gbps;
+ }
+ if (pf.isOneGbFd()) {
+ return Bandwidth.BW10Gbps;
+ }
+ if (pf.isTenGbFd()) {
+ return Bandwidth.BW10Gbps;
+ }
+ if (pf.isFortyGbFd()) {
+ return Bandwidth.BW40Gbps;
+ }
+ if (pf.isHundredGbFd()) {
+ return Bandwidth.BW100Gbps;
+ }
+ if (pf.isOneTbFd()) {
+ return Bandwidth.BW1Tbps;
+ }
+
+ return Bandwidth.BWUNK;
+ }
+
/**
* Construct a new instance.
*
+ * @param broker Data broker service.
* @throws InterruptedException
* The calling thread was interrupted.
*/
- public AdSalInventory() throws InterruptedException {
+ public AdSalInventory(DataBroker broker) throws InterruptedException {
Bundle bundle = FrameworkUtil.getBundle(AdSalInventory.class);
if (bundle == null) {
// This should never happen.
// Wait for mandatory OSGi services to be registered.
String container = GlobalConstants.DEFAULT.toString();
- new ServiceWaiter<ISwitchManager>(bc, ISwitchManager.class, container).
- await();
+ switchManager = new ServiceWaiter<ISwitchManager>(
+ bc, ISwitchManager.class, container).await();
connectionManager = new ServiceWaiter<IConnectionManager>(
- bc, IConnectionManager.class).await();
+ bc, IConnectionManager.class).
+ setFilter(ServiceWaiter.PROP_SCOPE, ServiceWaiter.SCOPE_GLOBAL).
+ await();
+ inventoryOut = new ServiceWaiter<IPluginOutInventoryService>(
+ bc, IPluginOutInventoryService.class, container).await();
+ inventoryOutGlobal = new ServiceWaiter<IPluginOutInventoryService>(
+ bc, IPluginOutInventoryService.class).
+ setFilter(ServiceWaiter.PROP_SCOPE, ServiceWaiter.SCOPE_GLOBAL).
+ await();
+
+ inventoryTimer.set(new Timer("AD-SAL inventory timer"));
// Register AD-SAL inventory listener.
Dictionary<String, Object> props = new Hashtable<>();
// Wait for sal-compatibility services to be registered.
new ServiceWaiter<IPluginInInventoryService>(
bc, IPluginInInventoryService.class, container).await();
+ new ServiceWaiter<IPluginInInventoryService>(
+ bc, IPluginInInventoryService.class).await();
new ServiceWaiter<IPluginInFlowProgrammerService>(
bc, IPluginInFlowProgrammerService.class).await();
+ // Register MD-SAL inventory listeners.
+ Set<DataStoreListener<?, ?>> mdSet = new HashSet<>();
+ dataListeners.set(mdSet);
+ mdSet.add(new MdNodeListener(broker, this));
+ mdSet.add(new MdPortListener(broker, this));
+
LOG.debug("AD-SAL inventory management has been initialized.");
}
+ /**
+ * Notify that the given node has been updated.
+ *
+ * @param nid The MD-SAL node identifier.
+ * @param fn A {@link FlowNode} instance.
+ * @param type An {@link UpdateType} instance which indicates the type of
+ * the event.
+ */
+ public void notifyNodeUpdated(String nid, FlowNode fn, UpdateType type) {
+ final Node node = toAdNode(nid);
+ Set<Property> props = toProperties(node, fn);
+ adNodes.put(node, props);
+
+ if (type == UpdateType.ADDED) {
+ Timer timer = inventoryTimer.get();
+ if (timer != null) {
+ TimerTask task = new TimerTask() {
+ @Override
+ public void run() {
+ publishNodeAdded(node);
+ }
+ };
+ timer.schedule(task, COMPAT_TIMEOUT);
+ }
+ } else {
+ inventoryOutGlobal.updateNode(node, type, props);
+ inventoryOut.updateNode(node, type, props);
+ }
+ }
+
+ /**
+ * Notify that the given node has been removed.
+ *
+ * @param nid The MD-SAL node identifier.
+ */
+ public void notifyNodeRemoved(String nid) {
+ Node node = toAdNode(nid);
+ adNodes.remove(node);
+
+ Set<Property> props = Collections.<Property>emptySet();
+ UpdateType type = UpdateType.REMOVED;
+ inventoryOutGlobal.updateNode(node, type, props);
+ inventoryOut.updateNode(node, type, props);
+ }
+
+ /**
+ * Notify that the given node connector has been updated.
+ *
+ * @param pid The MD-SAL port identifier.
+ * @param fcp A {@link FlowCapablePort} instance.
+ * @param type An {@link UpdateType} instance which indicates the type of
+ * the event.
+ */
+ public void notifyPortUpdated(String pid, FlowCapablePort fcp,
+ UpdateType type) {
+ final NodeConnector nc = toAdNodeConnector(pid);
+ Set<Property> props = toProperties(fcp);
+ adNodeConnectors.put(nc, props);
+
+ if (type == UpdateType.ADDED) {
+ Timer timer = inventoryTimer.get();
+ if (timer != null) {
+ TimerTask task = new TimerTask() {
+ @Override
+ public void run() {
+ publishPortAdded(nc);
+ }
+ };
+ timer.schedule(task, COMPAT_TIMEOUT);
+ }
+ } else {
+ inventoryOutGlobal.updateNodeConnector(nc, type, props);
+ inventoryOut.updateNodeConnector(nc, type, props);
+ }
+ }
+
+ /**
+ * Notify that the given node connector has been removed.
+ *
+ * @param pid The MD-SAL node connector identifier.
+ */
+ public void notifyPortRemoved(String pid) {
+ NodeConnector nc = toAdNodeConnector(pid);
+ adNodeConnectors.remove(nc);
+
+ Set<Property> props = Collections.<Property>emptySet();
+ UpdateType type = UpdateType.REMOVED;
+ inventoryOutGlobal.updateNodeConnector(nc, type, props);
+ inventoryOut.updateNodeConnector(nc, type, props);
+ }
+
/**
* Wait for the AD-SAL switch manager to detect the given node.
*
}
}
- /**
- * Stop the service.
- */
- public void close() {
- ServiceRegistration<?> reg = inventoryListener.getAndSet(null);
- if (reg != null) {
- try {
- reg.unregister();
- } catch (RuntimeException e) {
- LOG.warn("Failed to unregister IInventoryListener.", e);
- }
- }
- }
-
/**
* Wait for the given AD-SAL node to be created.
*
throw new IllegalStateException(msg);
}
+ /**
+ * Publish AD-SAL node creation event by force.
+ *
+ * @param node A {@link Node} instance.
+ */
+ private void publishNodeAdded(Node node) {
+ Set<Property> props = adNodes.get(node);
+ if (props != null && !switchManager.getNodes().contains(node)) {
+ LOG.warn("Notifying AD-SAL node creation: {}", node);
+ UpdateType type = UpdateType.ADDED;
+ inventoryOutGlobal.updateNode(node, type, props);
+ inventoryOut.updateNode(node, type, props);
+ }
+ }
+
+ /**
+ * Publish AD-SAL node connector creation event by force.
+ *
+ * @param nc A {@link NodeConnector} instance.
+ */
+ private void publishPortAdded(NodeConnector nc) {
+ Set<Property> props = adNodeConnectors.get(nc);
+ if (props == null) {
+ // The target node connector is already removed.
+ return;
+ }
+
+ Node node = nc.getNode();
+ Set<NodeConnector> ncSet = switchManager.getNodeConnectors(node);
+ if (ncSet == null || !ncSet.contains(nc)) {
+ LOG.warn("Notifying AD-SAL node connector creation: {}", nc);
+ UpdateType type = UpdateType.ADDED;
+ inventoryOutGlobal.updateNodeConnector(nc, type, props);
+ inventoryOut.updateNodeConnector(nc, type, props);
+ }
+ }
+
// IInventoryListener
/**
notifyAll();
}
}
+
+ // AutoCloseable
+
+ /**
+ * Close this instance.
+ */
+ @Override
+ public void close() {
+ Timer timer = inventoryTimer.getAndSet(null);
+ if (timer != null) {
+ timer.cancel();
+ }
+
+ ServiceRegistration<?> reg = inventoryListener.getAndSet(null);
+ if (reg != null) {
+ try {
+ reg.unregister();
+ } catch (RuntimeException e) {
+ LOG.debug("Failed to unregister IInventoryListener.", e);
+ }
+ }
+
+ Set<DataStoreListener<?, ?>> mdSet = dataListeners.getAndSet(null);
+ if (mdSet != null) {
+ for (DataStoreListener<?, ?> dsl: mdSet) {
+ dsl.close();
+ }
+ }
+ }
}
--- /dev/null
+/*
+ * Copyright (c) 2015 NEC Corporation
+ * 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.vtn.manager.it.ofmock.impl;
+
+import java.util.Set;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+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.common.api.data.LogicalDatastoreType;
+
+import org.opendaylight.controller.sal.core.UpdateType;
+
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.types.rev150209.VtnUpdateType;
+
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey;
+
+/**
+ * {@code MdNodeListener} listens changes to the MD-SAL node information.
+ */
+public final class MdNodeListener
+ extends DataStoreListener<FlowCapableNode, Void> {
+ /**
+ * Logger instance.
+ */
+ private static final Logger LOG =
+ LoggerFactory.getLogger(MdNodeListener.class);
+
+ /**
+ * AD-SAL inventory manager.
+ */
+ private final AdSalInventory adInventory;
+
+ /**
+ * Construct a new instance.
+ *
+ * @param broker Data broker service.
+ * @param adsal AD-SAL inventory manager.
+ */
+ public MdNodeListener(DataBroker broker, AdSalInventory adsal) {
+ super(FlowCapableNode.class);
+ adInventory = adsal;
+ registerListener(broker, LogicalDatastoreType.OPERATIONAL,
+ DataChangeScope.SUBTREE);
+ }
+
+ /**
+ * Return a MD-SAL node identifier in the given instance identifier.
+ *
+ * @param path An {@link InstanceIdentifier} instance.
+ * @return A MD-SAL node identifier if found.
+ * {@code null} if not found.
+ */
+ private String getNodeIdentifier(InstanceIdentifier<?> path) {
+ if (path == null) {
+ return null;
+ }
+
+ NodeKey key = path.firstKeyOf(Node.class, NodeKey.class);
+ if (key == null) {
+ return null;
+ }
+
+ NodeId nodeId = key.getId();
+ return (nodeId == null) ? null : nodeId.getValue();
+ }
+
+ /**
+ * Invoked when a MD-SAL node has been updated.
+ *
+ * @param path Path to the flow-capable-node.
+ * @param fcn A {@link FlowCapableNode} instance.
+ * @param type An {@link UpdateType} instance which indicates the type of
+ * the event.
+ */
+ private void nodeUpdated(InstanceIdentifier<FlowCapableNode> path,
+ FlowCapableNode fcn, UpdateType type) {
+ if (fcn == null) {
+ return;
+ }
+
+ String nid = getNodeIdentifier(path);
+ if (nid != null) {
+ LOG.trace("{}: MD-SAL node has been updated: nid={}, fcn={}",
+ type, nid, fcn);
+ adInventory.notifyNodeUpdated(nid, fcn, type);
+ }
+ }
+
+ /**
+ * Invoked when a MD-SAL node has been removed.
+ *
+ * @param path Path to the flow-capable-node.
+ */
+ private void nodeRemoved(InstanceIdentifier<FlowCapableNode> path) {
+ String nid = getNodeIdentifier(path);
+ if (nid != null) {
+ LOG.trace("REMOVED: MD-SAL node has been removed: {}", nid);
+ adInventory.notifyNodeRemoved(nid);
+ }
+ }
+
+ // DataStoreListener
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected Void enterEvent(
+ AsyncDataChangeEvent<InstanceIdentifier<?>, DataObject> ev) {
+ return null;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected void exitEvent(Void ectx) {
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected void onCreated(Void ectx,
+ InstanceIdentifier<FlowCapableNode> path,
+ FlowCapableNode data) {
+ nodeUpdated(path, data, UpdateType.ADDED);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected void onUpdated(Void ectx,
+ InstanceIdentifier<FlowCapableNode> path,
+ FlowCapableNode oldData, FlowCapableNode newData) {
+ nodeUpdated(path, newData, UpdateType.CHANGED);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected void onRemoved(Void ectx,
+ InstanceIdentifier<FlowCapableNode> path,
+ FlowCapableNode data) {
+ nodeRemoved(path);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected InstanceIdentifier<FlowCapableNode> getWildcardPath() {
+ return InstanceIdentifier.builder(Nodes.class).child(Node.class).
+ augmentation(FlowCapableNode.class).build();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected Logger getLogger() {
+ return LOG;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected Set<VtnUpdateType> getRequiredEvents() {
+ return null;
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2015 NEC Corporation
+ * 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.vtn.manager.it.ofmock.impl;
+
+import java.util.Set;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+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.common.api.data.LogicalDatastoreType;
+
+import org.opendaylight.controller.sal.core.UpdateType;
+
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.types.rev150209.VtnUpdateType;
+
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNodeConnector;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnector;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnectorKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
+
+/**
+ * {@code MdPortListener} listens changes to the MD-SAL node connector
+ * information.
+ */
+public final class MdPortListener
+ extends DataStoreListener<FlowCapableNodeConnector, Void> {
+ /**
+ * Logger instance.
+ */
+ private static final Logger LOG =
+ LoggerFactory.getLogger(MdPortListener.class);
+
+ /**
+ * AD-SAL inventory manager.
+ */
+ private final AdSalInventory adInventory;
+
+ /**
+ * Construct a new instance.
+ *
+ * @param broker Data broker service.
+ * @param adsal AD-SAL inventory manager.
+ */
+ public MdPortListener(DataBroker broker, AdSalInventory adsal) {
+ super(FlowCapableNodeConnector.class);
+ adInventory = adsal;
+ registerListener(broker, LogicalDatastoreType.OPERATIONAL,
+ DataChangeScope.SUBTREE);
+ }
+
+ /**
+ * Return a MD-SAL node connector identifier in the given instance
+ * identifier.
+ *
+ * @param path An {@link InstanceIdentifier} instance.
+ * @return A MD-SAL node connector identifier if found.
+ * {@code null} if not found.
+ */
+ private String getPortIdentifier(InstanceIdentifier<?> path) {
+ if (path == null) {
+ return null;
+ }
+
+ NodeConnectorKey key =
+ path.firstKeyOf(NodeConnector.class, NodeConnectorKey.class);
+ if (key == null) {
+ return null;
+ }
+
+ NodeConnectorId ncId = key.getId();
+ return (ncId == null) ? null : ncId.getValue();
+ }
+
+ /**
+ * Invoked when a MD-SAL node connector has been updated.
+ *
+ * @param path Path to the flow-capable-node-connector.
+ * @param fcnc A {@link FlowCapableNodeConnector} instance.
+ * @param type An {@link UpdateType} instance which indicates the type of
+ * the event.
+ */
+ private void portUpdated(InstanceIdentifier<FlowCapableNodeConnector> path,
+ FlowCapableNodeConnector fcnc, UpdateType type) {
+ if (fcnc == null) {
+ return;
+ }
+
+ String pid = getPortIdentifier(path);
+ if (pid != null) {
+ LOG.trace("{}: MD-SAL node connector has been updated: pid={}, " +
+ "fcnc={}", type, pid, fcnc);
+ adInventory.notifyPortUpdated(pid, fcnc, type);
+ }
+ }
+
+ /**
+ * Invoked when a MD-SAL node connector has been removed.
+ *
+ * @param path Path to the flow-capable-node-capable.
+ */
+ private void portRemoved(
+ InstanceIdentifier<FlowCapableNodeConnector> path) {
+ String pid = getPortIdentifier(path);
+ if (pid != null) {
+ LOG.trace("REMOVED: MD-SAL node connector has been removed: {}",
+ pid);
+ adInventory.notifyPortRemoved(pid);
+ }
+ }
+
+ // DataStoreListener
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected Void enterEvent(
+ AsyncDataChangeEvent<InstanceIdentifier<?>, DataObject> ev) {
+ return null;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected void exitEvent(Void ectx) {
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected void onCreated(Void ectx,
+ InstanceIdentifier<FlowCapableNodeConnector> path,
+ FlowCapableNodeConnector data) {
+ portUpdated(path, data, UpdateType.ADDED);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected void onUpdated(Void ectx,
+ InstanceIdentifier<FlowCapableNodeConnector> path,
+ FlowCapableNodeConnector oldData,
+ FlowCapableNodeConnector newData) {
+ portUpdated(path, newData, UpdateType.CHANGED);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected void onRemoved(Void ectx,
+ InstanceIdentifier<FlowCapableNodeConnector> path,
+ FlowCapableNodeConnector data) {
+ portRemoved(path);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected InstanceIdentifier<FlowCapableNodeConnector> getWildcardPath() {
+ return InstanceIdentifier.builder(Nodes.class).child(Node.class).
+ child(NodeConnector.class).
+ augmentation(FlowCapableNodeConnector.class).build();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected Logger getLogger() {
+ return LOG;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected Set<VtnUpdateType> getRequiredEvents() {
+ return null;
+ }
+}
public void initialize() throws InterruptedException {
if (adSalInventory == null) {
try {
- adSalInventory = new AdSalInventory();
+ adSalInventory = new AdSalInventory(dataBroker);
} catch (RuntimeException e) {
String msg = "Failed to initialize AD-SAL inventory: " +
e.getMessage();
package org.opendaylight.vtn.manager.it.ofmock.impl;
import java.util.Collection;
+import java.util.HashMap;
import java.util.Iterator;
+import java.util.Map;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
*/
static final String PROP_CONTAINER = "containerName";
+ /**
+ * The name of the OSGi service property which specifies the scope of the
+ * service.
+ */
+ static final String PROP_SCOPE = "scope";
+
+ /**
+ * The value of the OSGi service property which specifies the global scope.
+ * service.
+ */
+ static final String SCOPE_GLOBAL = "Global";
+
/**
* An OSGi bundle context for this OSGi bundle.
*/
private final Class<T> serviceType;
/**
- * OSGi service filter for retrieving.
+ * A set of OSGi service filters for retrieving.
*/
- private final String serviceFilter;
+ private final Map<String, String> serviceFilters = new HashMap<>();
/**
* OSGI service implementation to be returned.
public ServiceWaiter(BundleContext bc, Class<T> type, String cname) {
bundleContext = bc;
serviceType = type;
+ setFilter(Constants.OBJECTCLASS, type.getName()).
+ setFilter(PROP_CONTAINER, cname);
+ }
- // Construct a OSGi service filter.
- String objFilter = new StringBuilder("(").
- append(Constants.OBJECTCLASS).append('=').append(type.getName()).
- append(')').toString();
- if (cname == null) {
- serviceFilter = objFilter;
+ /**
+ * Set OSGi service filters for retrieving.
+ *
+ * @param name The name of the filter.
+ * @param value The value to be associated with the given filter name.
+ * @return This instance.
+ */
+ public ServiceWaiter<T> setFilter(String name, String value) {
+ if (value == null) {
+ serviceFilters.remove(name);
} else {
- StringBuilder builder = new StringBuilder("(&").
- append(objFilter).append('(').append(PROP_CONTAINER).
- append('=').append(cname).append("))");
- serviceFilter = builder.toString();
+ serviceFilters.put(name, value);
}
-
- // Try to get service instance.
- getService();
+ return this;
}
/**
* The calling thread was interrupted.
*/
public T await() throws InterruptedException {
- synchronized (this) {
- if (serviceInstance != null) {
- return serviceInstance;
- }
+ // Construct a OSGi service filter.
+ StringBuilder builder = new StringBuilder("(&");
+ for (Map.Entry<String, String> entry: serviceFilters.entrySet()) {
+ builder.append('(').append(entry.getKey()).append('=').
+ append(entry.getValue()).append(')');
}
+ String filter = builder.append(')').toString();
+ LOG.trace("Searching for {} service: filter={}",
+ serviceType.getSimpleName(), filter);
+
try {
- bundleContext.addServiceListener(this, serviceFilter);
+ bundleContext.addServiceListener(this, filter);
} catch (Exception e) {
throw new IllegalStateException(
"Failed to add OSGi service listener.", e);
}
try {
- // We need to check the service again in order to avoid race
- // condition with service event.
- T impl = getService();
+ // We need to check the service in order to avoid race condition
+ // with service event.
+ T impl = getService(filter);
if (impl == null) {
+ LOG.trace("Waiting for {} service to be registered: filter={}",
+ serviceType.getSimpleName(), filter);
impl = awaitImpl();
}
* The calling thread was interrupted.
*/
private synchronized T awaitImpl() throws InterruptedException {
- LOG.trace("Waiting for {} service to be registered.",
- serviceType.getSimpleName());
-
long timeout = OfMockProvider.TASK_TIMEOUT;
long deadline = System.currentTimeMillis() + timeout;
do {
/**
* Search for the target OSGi service implementation.
*
+ * @param filter An OSGi service filter.
* @return An implementation of the target OSGi service on success.
* {@code null} on failure.
*/
- private T getService() {
+ private T getService(String filter) {
synchronized (this) {
if (serviceInstance != null) {
return serviceInstance;
Collection<ServiceReference<T>> c;
try {
- c = bundleContext.getServiceReferences(serviceType, serviceFilter);
+ c = bundleContext.getServiceReferences(serviceType, filter);
} catch (Exception e) {
String msg = "Failed to get OSGi service reference: " +
serviceType.getSimpleName();
public VtnNodeListener(DataBroker broker) {
super(VtnNode.class);
registerListener(broker, LogicalDatastoreType.OPERATIONAL,
- DataChangeScope.BASE);
+ DataChangeScope.ONE);
}
/**
public VtnPortListener(DataBroker broker) {
super(VtnPort.class);
registerListener(broker, LogicalDatastoreType.OPERATIONAL,
- DataChangeScope.BASE);
+ DataChangeScope.SUBTREE);
}
/**
<module>option</module>
<module>util</module>
<module>common</module>
- <!--
<module>core</module>
<module>northbound</module>
- -->
</modules>
</project>