<feature version='${mdsal.version}'>odl-mdsal-broker</feature>
<feature version='${project.version}'>odl-ovsdb-hwvtepsouthbound-api</feature>
<bundle>mvn:org.opendaylight.ovsdb/hwvtepsouthbound-impl/${project.version}</bundle>
+ <bundle>mvn:com.fasterxml.jackson.core/jackson-annotations/${jackson.version}</bundle>
+ <bundle>mvn:com.fasterxml.jackson.core/jackson-core/${jackson.version}</bundle>
+ <bundle>mvn:com.fasterxml.jackson.core/jackson-databind/${jackson.version}</bundle>
+ <bundle>mvn:com.fasterxml.jackson.datatype/jackson-datatype-json-org/${jackson.version}</bundle>
+ <bundle>wrap:mvn:org.json/json/${org.json.version}</bundle>
<configfile finalname="${configfile.directory}/hwvtepsouthbound.xml">mvn:org.opendaylight.ovsdb/hwvtepsouthbound-impl/${project.version}/xml/config</configfile>
</feature>
<feature name='odl-ovsdb-hwvtepsouthbound-rest' version='${project.version}' description='OpenDaylight :: hwvtepsouthbound :: REST'>
<artifactId>hwvtepsouthbound-api</artifactId>
<version>${project.version}</version>
</dependency>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>library</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>schema.hardwarevtep</artifactId>
+ <version>${project.version}</version>
+ </dependency>
<!-- Testing Dependencies -->
<dependency>
<build>
<plugins>
+ <plugin>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>maven-bundle-plugin</artifactId>
+ <configuration>
+ <instructions>
+ <Private-Package>org.opendaylight.ovsdb.lib.*,org.opendaylight.ovsdb.schema.hardwarevtep</Private-Package>
+ <Export-Package>org.opendaylight.ovsdb.hwvtepsouthbound.*,org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hwvtepsouthbound.impl.rev150901</Export-Package>
+ </instructions>
+ </configuration>
+ </plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-checkstyle-plugin</artifactId>
<type xmlns:binding="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding">binding:binding-broker-osgi-registry</type>
<name>binding-osgi-broker</name>
</broker>
+ <schema-service>
+ <type xmlns:dom="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom">dom:schema-service</type>
+ <name>yang-schema-service</name>
+ </schema-service>
+ <binding-normalized-node-serializer>
+ <type xmlns:binding="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding">binding:binding-normalized-node-serializer</type>
+ <name>runtime-mapping-singleton</name>
+ </binding-normalized-node-serializer>
+ <clustering-entity-ownership-service>
+ <type xmlns:ns="urn:opendaylight:params:xml:ns:yang:controller:md:sal:core:spi:entity-ownership-service">ns:entity-ownership-service</type>
+ <name>entity-ownership-service</name>
+ </clustering-entity-ownership-service>
</module>
</modules>
</data>
--- /dev/null
+/*
+ * Copyright (c) 2015 Ericsson India Global Services Pvt Ltd. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.ovsdb.hwvtepsouthbound;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.ExecutionException;
+
+import javax.annotation.Nonnull;
+
+import org.opendaylight.controller.md.sal.common.api.clustering.Entity;
+import org.opendaylight.controller.md.sal.common.api.clustering.EntityOwnershipCandidateRegistration;
+import org.opendaylight.ovsdb.hwvtepsouthbound.transact.TransactCommand;
+import org.opendaylight.ovsdb.hwvtepsouthbound.transact.TransactInvoker;
+import org.opendaylight.ovsdb.hwvtepsouthbound.transact.TransactInvokerImpl;
+import org.opendaylight.ovsdb.hwvtepsouthbound.transactions.md.TransactionInvoker;
+import org.opendaylight.ovsdb.lib.EchoServiceCallbackFilters;
+import org.opendaylight.ovsdb.lib.LockAquisitionCallback;
+import org.opendaylight.ovsdb.lib.LockStolenCallback;
+import org.opendaylight.ovsdb.lib.MonitorCallBack;
+import org.opendaylight.ovsdb.lib.MonitorHandle;
+import org.opendaylight.ovsdb.lib.OvsdbClient;
+import org.opendaylight.ovsdb.lib.OvsdbConnectionInfo;
+import org.opendaylight.ovsdb.lib.message.MonitorRequest;
+import org.opendaylight.ovsdb.lib.message.MonitorRequestBuilder;
+import org.opendaylight.ovsdb.lib.message.MonitorSelect;
+import org.opendaylight.ovsdb.lib.message.TableUpdates;
+import org.opendaylight.ovsdb.lib.notation.Row;
+import org.opendaylight.ovsdb.lib.operations.Operation;
+import org.opendaylight.ovsdb.lib.operations.OperationResult;
+import org.opendaylight.ovsdb.lib.operations.TransactionBuilder;
+import org.opendaylight.ovsdb.lib.schema.DatabaseSchema;
+import org.opendaylight.ovsdb.lib.schema.GenericTableSchema;
+import org.opendaylight.ovsdb.lib.schema.TableSchema;
+import org.opendaylight.ovsdb.lib.schema.typed.TypedBaseTable;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.global.attributes.ConnectionInfo;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.NodeKey;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.collect.Lists;
+import com.google.common.util.concurrent.ListenableFuture;
+
+public class HwvtepConnectionInstance implements OvsdbClient{
+ private static final Logger LOG = LoggerFactory.getLogger(HwvtepConnectionInstance.class);
+ private ConnectionInfo connectionInfo;
+ private OvsdbClient client;
+ private InstanceIdentifier<Node> instanceIdentifier;
+ private TransactionInvoker txInvoker;
+ private Map<DatabaseSchema,TransactInvoker> transactInvokers;
+ private MonitorCallBack callback;
+ private volatile boolean hasDeviceOwnership = false;
+ private Entity connectedEntity;
+ private EntityOwnershipCandidateRegistration deviceOwnershipCandidateRegistration;
+
+
+ HwvtepConnectionInstance (ConnectionInfo key,OvsdbClient client,
+ InstanceIdentifier<Node> iid, TransactionInvoker txInvoker) {
+ this.connectionInfo = key;
+ this.client = client;
+ this.instanceIdentifier = iid;
+ this.txInvoker = txInvoker;
+ }
+
+ public void transact(TransactCommand command) {
+ for (TransactInvoker transactInvoker: transactInvokers.values()) {
+ transactInvoker.invoke(command);
+ }
+ }
+
+ public void registerCallbacks() {
+ if ( this.callback == null) {
+ try {
+ List<String> databases = getDatabases().get();
+ this.callback = new HwvtepMonitorCallback(this,txInvoker);
+ for (String database : databases) {
+ DatabaseSchema dbSchema = getSchema(database).get();
+ if (dbSchema != null) {
+ monitorAllTables(database, dbSchema);
+ } else {
+ LOG.warn("No schema reported for database {} for key {}",database,connectionInfo);
+ }
+ }
+ } catch (InterruptedException | ExecutionException e) {
+ LOG.warn("Exception attempting to registerCallbacks {}: {}",connectionInfo,e);
+ }
+ }
+ }
+
+ public void createTransactInvokers() {
+ if (transactInvokers == null) {
+ try {
+ transactInvokers = new HashMap<DatabaseSchema,TransactInvoker>();
+ List<String> databases = getDatabases().get();
+ for (String database : databases) {
+ DatabaseSchema dbSchema = getSchema(database).get();
+ if (dbSchema != null) {
+ transactInvokers.put(dbSchema, new TransactInvokerImpl(this,dbSchema));
+ }
+ }
+ } catch (InterruptedException | ExecutionException e) {
+ LOG.warn("Exception attempting to createTransactionInvokers {}: {}",connectionInfo,e);
+ }
+ }
+ }
+
+ private void monitorAllTables(String database, DatabaseSchema dbSchema) {
+ Set<String> tables = dbSchema.getTables();
+ if (tables != null) {
+ List<MonitorRequest<GenericTableSchema>> monitorRequests = Lists.newArrayList();
+ for (String tableName : tables) {
+ GenericTableSchema tableSchema = dbSchema.table(tableName, GenericTableSchema.class);
+ Set<String> columns = tableSchema.getColumns();
+ MonitorRequestBuilder<GenericTableSchema> monitorBuilder = MonitorRequestBuilder.builder(tableSchema);
+ for (String column : columns) {
+ monitorBuilder.addColumn(column);
+ }
+ monitorRequests.add(monitorBuilder.with(new MonitorSelect(true, true, true, true)).build());
+ }
+ this.callback.update(monitor(dbSchema, monitorRequests, callback),dbSchema);
+ } else {
+ LOG.warn("No tables for schema {} for database {} for key {}",dbSchema,database,connectionInfo);
+ }
+ }
+
+ public ListenableFuture<List<String>> getDatabases() {
+ return client.getDatabases();
+ }
+
+ public ListenableFuture<DatabaseSchema> getSchema(String database) {
+ return client.getSchema(database);
+ }
+
+ public TransactionBuilder transactBuilder(DatabaseSchema dbSchema) {
+ return client.transactBuilder(dbSchema);
+ }
+
+ public ListenableFuture<List<OperationResult>> transact(DatabaseSchema dbSchema, List<Operation> operations) {
+ return client.transact(dbSchema, operations);
+ }
+
+ public <E extends TableSchema<E>> TableUpdates monitor(DatabaseSchema schema,
+ List<MonitorRequest<E>> monitorRequests, MonitorCallBack callback) {
+ return client.monitor(schema, monitorRequests, callback);
+ }
+
+ @Override
+ public <E extends TableSchema<E>> TableUpdates monitor(DatabaseSchema schema,
+ List<MonitorRequest<E>> monitorRequests, MonitorHandle monitorHandle, MonitorCallBack callback) {
+ return null;
+ }
+
+ public void cancelMonitor(MonitorHandle handler) {
+ client.cancelMonitor(handler);
+ }
+
+ public void lock(String lockId, LockAquisitionCallback lockedCallBack, LockStolenCallback stolenCallback) {
+ client.lock(lockId, lockedCallBack, stolenCallback);
+ }
+
+ public ListenableFuture<Boolean> steal(String lockId) {
+ return client.steal(lockId);
+ }
+
+ public ListenableFuture<Boolean> unLock(String lockId) {
+ return client.unLock(lockId);
+ }
+
+ public void startEchoService(EchoServiceCallbackFilters callbackFilters) {
+ client.startEchoService(callbackFilters);
+ }
+
+ public void stopEchoService() {
+ client.stopEchoService();
+ }
+
+ public OvsdbConnectionInfo getConnectionInfo() {
+ return client.getConnectionInfo();
+ }
+
+ public boolean isActive() {
+ return client.isActive();
+ }
+
+ public void disconnect() {
+ client.disconnect();
+ }
+
+ public DatabaseSchema getDatabaseSchema(String dbName) {
+ return client.getDatabaseSchema(dbName);
+ }
+
+ public <T extends TypedBaseTable<?>> T createTypedRowWrapper(Class<T> klazz) {
+ return client.createTypedRowWrapper(klazz);
+ }
+
+ public <T extends TypedBaseTable<?>> T createTypedRowWrapper(DatabaseSchema dbSchema, Class<T> klazz) {
+ return client.createTypedRowWrapper(dbSchema, klazz);
+ }
+
+ public <T extends TypedBaseTable<?>> T getTypedRowWrapper(Class<T> klazz, Row<GenericTableSchema> row) {
+ return client.getTypedRowWrapper(klazz, row);
+ }
+
+ public ConnectionInfo getMDConnectionInfo() {
+ return connectionInfo;
+ }
+
+ public void setMDConnectionInfo(ConnectionInfo key) {
+ this.connectionInfo = key;
+ }
+
+ public InstanceIdentifier<Node> getInstanceIdentifier() {
+ return instanceIdentifier;
+ }
+
+ public NodeKey getNodeKey() {
+ //TODO: What is the alternative here?
+ return getInstanceIdentifier().firstKeyOf(Node.class, NodeKey.class);
+ }
+
+ public NodeId getNodeId() {
+ return getNodeKey().getNodeId();
+ }
+
+ public void setInstanceIdentifier(InstanceIdentifier<Node> iid) {
+ this.instanceIdentifier = iid;
+ }
+
+ public Entity getConnectedEntity() {
+ return this.connectedEntity;
+ }
+
+ public void setConnectedEntity(Entity entity ) {
+ this.connectedEntity = entity;
+ }
+
+ public Boolean hasOvsdbClient(OvsdbClient otherClient) {
+ return client.equals(otherClient);
+ }
+
+ public Boolean getHasDeviceOwnership() {
+ return Boolean.valueOf(hasDeviceOwnership);
+ }
+
+ public void setHasDeviceOwnership(Boolean hasDeviceOwnership) {
+ if (hasDeviceOwnership != null) {
+ this.hasDeviceOwnership = hasDeviceOwnership.booleanValue();
+ }
+ }
+
+ public void setDeviceOwnershipCandidateRegistration(@Nonnull EntityOwnershipCandidateRegistration registration) {
+ this.deviceOwnershipCandidateRegistration = registration;
+ }
+
+ public void closeDeviceOwnershipCandidateRegistration() {
+ if (deviceOwnershipCandidateRegistration != null) {
+ this.deviceOwnershipCandidateRegistration.close();
+ setHasDeviceOwnership(Boolean.FALSE);
+ }
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2015 Ericsson India Global Services Pvt Ltd. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.ovsdb.hwvtepsouthbound;
+
+import static org.opendaylight.ovsdb.lib.operations.Operations.op;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ExecutionException;
+
+import javax.annotation.Nonnull;
+
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.common.api.clustering.CandidateAlreadyRegisteredException;
+import org.opendaylight.controller.md.sal.common.api.clustering.Entity;
+import org.opendaylight.controller.md.sal.common.api.clustering.EntityOwnershipCandidateRegistration;
+import org.opendaylight.controller.md.sal.common.api.clustering.EntityOwnershipChange;
+import org.opendaylight.controller.md.sal.common.api.clustering.EntityOwnershipListener;
+import org.opendaylight.controller.md.sal.common.api.clustering.EntityOwnershipListenerRegistration;
+import org.opendaylight.controller.md.sal.common.api.clustering.EntityOwnershipService;
+import org.opendaylight.controller.md.sal.common.api.clustering.EntityOwnershipState;
+import org.opendaylight.ovsdb.hwvtepsouthbound.transactions.md.TransactionInvoker;
+import org.opendaylight.ovsdb.lib.OvsdbClient;
+import org.opendaylight.ovsdb.lib.OvsdbConnectionListener;
+import org.opendaylight.ovsdb.lib.operations.Operation;
+import org.opendaylight.ovsdb.lib.operations.OperationResult;
+import org.opendaylight.ovsdb.lib.operations.Select;
+import org.opendaylight.ovsdb.lib.schema.DatabaseSchema;
+import org.opendaylight.ovsdb.lib.schema.GenericTableSchema;
+import org.opendaylight.ovsdb.lib.schema.typed.TyperUtils;
+import org.opendaylight.ovsdb.schema.hardwarevtep.Global;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.global.attributes.ConnectionInfo;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.base.Optional;
+
+public class HwvtepConnectionManager implements OvsdbConnectionListener, AutoCloseable{
+ private Map<ConnectionInfo, HwvtepConnectionInstance> clients =
+ new ConcurrentHashMap<ConnectionInfo,HwvtepConnectionInstance>();
+ private static final Logger LOG = LoggerFactory.getLogger(HwvtepConnectionManager.class);
+ private static final String ENTITY_TYPE = "hwvtep";
+
+ private DataBroker db;
+ private TransactionInvoker txInvoker;
+ private Map<ConnectionInfo,InstanceIdentifier<Node>> instanceIdentifiers =
+ new ConcurrentHashMap<ConnectionInfo,InstanceIdentifier<Node>>();
+ private Map<Entity, HwvtepConnectionInstance> entityConnectionMap =
+ new ConcurrentHashMap<>();
+ private EntityOwnershipService entityOwnershipService;
+ private HwvtepDeviceEntityOwnershipListener hwvtepDeviceEntityOwnershipListener;
+
+ public HwvtepConnectionManager(DataBroker db, TransactionInvoker txInvoker,
+ EntityOwnershipService entityOwnershipService) {
+ this.db = db;
+ this.txInvoker = txInvoker;
+ this.entityOwnershipService = entityOwnershipService;
+ this.hwvtepDeviceEntityOwnershipListener = new HwvtepDeviceEntityOwnershipListener(this,entityOwnershipService);
+ }
+
+ @Override
+ public void close() throws Exception {
+ if (hwvtepDeviceEntityOwnershipListener != null) {
+ hwvtepDeviceEntityOwnershipListener.close();
+ }
+
+ for (OvsdbClient client: clients.values()) {
+ client.disconnect();
+ }
+ }
+
+ @Override
+ public void connected(@Nonnull final OvsdbClient client) {
+ HwvtepConnectionInstance hwClient = connectedButCallBacksNotRegistered(client);
+ registerEntityForOwnership(hwClient);
+ LOG.trace("connected client: {}", hwClient);
+ }
+
+ @Override
+ public void disconnected(OvsdbClient client) {
+ LOG.info("HWVTEP Disconnected from {}:{}. Cleaning up the operational data store"
+ ,client.getConnectionInfo().getRemoteAddress(),
+ client.getConnectionInfo().getRemotePort());
+ ConnectionInfo key = HwvtepSouthboundMapper.createConnectionInfo(client);
+ HwvtepConnectionInstance hwvtepConnectionInstance = getConnectionInstance(key);
+ if (hwvtepConnectionInstance != null) {
+ //TODO: txInvoker.invoke(new HwvtepNodeRemoveCommand(hwvtepConnectionInstance, null, null));
+ removeConnectionInstance(key);
+
+ // Unregister Cluster Ownership for ConnectionInfo
+ unregisterEntityForOwnership(hwvtepConnectionInstance);
+ } else {
+ LOG.warn("HWVTEP disconnected event did not find connection instance for {}", key);
+ }
+ LOG.trace("disconnected client: {}", client);
+ }
+
+ public HwvtepConnectionInstance connectedButCallBacksNotRegistered(final OvsdbClient externalClient) {
+ LOG.info("OVSDB Connection from {}:{}",externalClient.getConnectionInfo().getRemoteAddress(),
+ externalClient.getConnectionInfo().getRemotePort());
+ ConnectionInfo key = HwvtepSouthboundMapper.createConnectionInfo(externalClient);
+ HwvtepConnectionInstance hwvtepConnectionInstance = getConnectionInstance(key);
+
+ // Check if existing hwvtepConnectionInstance for the OvsdbClient present.
+ // In such cases, we will see if the hwvtepConnectionInstance has same externalClient.
+ if (hwvtepConnectionInstance != null) {
+ if (hwvtepConnectionInstance.hasOvsdbClient(externalClient)) {
+ LOG.warn("HWVTEP Connection Instance {} already exists for client {}", key, externalClient);
+ return hwvtepConnectionInstance;
+ }
+ LOG.warn("HWVTEP Connection Instance {} being replaced with client {}", key, externalClient);
+ hwvtepConnectionInstance.disconnect();
+
+ // Unregister Cluster Ownership for ConnectionInfo
+ // Because the hwvtepConnectionInstance is about to be completely replaced!
+ unregisterEntityForOwnership(hwvtepConnectionInstance);
+
+ removeConnectionInstance(key);
+ }
+
+ hwvtepConnectionInstance = new HwvtepConnectionInstance(key, externalClient, getInstanceIdentifier(key),
+ txInvoker);
+ hwvtepConnectionInstance.createTransactInvokers();
+ return hwvtepConnectionInstance;
+ }
+
+ /* TODO:
+ public OvsdbClient connect(InstanceIdentifier<Node> iid, OvsdbNodeAugmentation ovsdbNode)
+ throws UnknownHostException {
+ }
+
+ public void disconnect(OvsdbNodeAugmentation ovsdbNode) throws UnknownHostException {
+ OvsdbConnectionInstance client = getConnectionInstance(ovsdbNode.getConnectionInfo());
+
+ }
+
+ */
+
+ private void putConnectionInstance(ConnectionInfo key,HwvtepConnectionInstance instance) {
+ ConnectionInfo connectionInfo = HwvtepSouthboundMapper.suppressLocalIpPort(key);
+ clients.put(connectionInfo, instance);
+ LOG.info("Clients after put: {}", clients);
+ }
+
+ public HwvtepConnectionInstance getConnectionInstance(ConnectionInfo key) {
+ ConnectionInfo connectionInfo = HwvtepSouthboundMapper.suppressLocalIpPort(key);
+ return clients.get(connectionInfo);
+ }
+
+ private void removeConnectionInstance(ConnectionInfo key) {
+ ConnectionInfo connectionInfo = HwvtepSouthboundMapper.suppressLocalIpPort(key);
+ clients.remove(connectionInfo);
+ LOG.info("Clients after remove: {}", clients);
+ }
+
+ private void putInstanceIdentifier(ConnectionInfo key,InstanceIdentifier<Node> iid) {
+ ConnectionInfo connectionInfo = HwvtepSouthboundMapper.suppressLocalIpPort(key);
+ instanceIdentifiers.put(connectionInfo, iid);
+ }
+
+ public InstanceIdentifier<Node> getInstanceIdentifier(ConnectionInfo key) {
+ ConnectionInfo connectionInfo = HwvtepSouthboundMapper.suppressLocalIpPort(key);
+ InstanceIdentifier<Node> iid = instanceIdentifiers.get(connectionInfo);
+ return iid;
+ }
+
+ private void removeInstanceIdentifier(ConnectionInfo key) {
+ ConnectionInfo connectionInfo = HwvtepSouthboundMapper.suppressLocalIpPort(key);
+ instanceIdentifiers.remove(connectionInfo);
+ }
+
+ private void registerEntityForOwnership(HwvtepConnectionInstance hwvtepConnectionInstance) {
+
+ Entity candidateEntity = getEntityFromConnectionInstance(hwvtepConnectionInstance);
+ entityConnectionMap.put(candidateEntity, hwvtepConnectionInstance);
+ hwvtepConnectionInstance.setConnectedEntity(candidateEntity);
+
+ try {
+ EntityOwnershipCandidateRegistration registration =
+ entityOwnershipService.registerCandidate(candidateEntity);
+ hwvtepConnectionInstance.setDeviceOwnershipCandidateRegistration(registration);
+ LOG.info("HWVTEP entity {} is registered for ownership.", candidateEntity);
+
+ //If entity already has owner, it won't get notification from EntityOwnershipService
+ //so cache the connection instances.
+ Optional<EntityOwnershipState> ownershipStateOpt =
+ entityOwnershipService.getOwnershipState(candidateEntity);
+ if (ownershipStateOpt.isPresent()) {
+ EntityOwnershipState ownershipState = ownershipStateOpt.get();
+ if (ownershipState.hasOwner() && !ownershipState.isOwner()) {
+ if (getConnectionInstance(hwvtepConnectionInstance.getMDConnectionInfo()) != null) {
+ LOG.info("OVSDB entity {} is already owned by other southbound plugin "
+ + "instance, so *this* instance is NOT an OWNER of the device",
+ hwvtepConnectionInstance.getConnectionInfo());
+ putConnectionInstance(hwvtepConnectionInstance.getMDConnectionInfo(),hwvtepConnectionInstance);
+ }
+ }
+ }
+ } catch (CandidateAlreadyRegisteredException e) {
+ LOG.warn("OVSDB entity {} was already registered for {} ownership", candidateEntity, e);
+ }
+
+ }
+
+ private Global getHwvtepGlobalTableEntry(HwvtepConnectionInstance connectionInstance) {
+ DatabaseSchema dbSchema = null;
+ Global globalRow = null;
+
+ try {
+ dbSchema = connectionInstance.getSchema(HwvtepSchemaConstants.databaseName).get();
+ } catch (InterruptedException | ExecutionException e) {
+ LOG.warn("Not able to fetch schema for database {} from device {}",
+ HwvtepSchemaConstants.databaseName,connectionInstance.getConnectionInfo(),e);
+ }
+
+ if (dbSchema != null) {
+ GenericTableSchema hwvtepSchema = TyperUtils.getTableSchema(dbSchema, Global.class);
+
+ List<String> hwvtepTableColumn = new ArrayList<String>();
+ hwvtepTableColumn.addAll(hwvtepSchema.getColumns());
+ Select<GenericTableSchema> selectOperation = op.select(hwvtepSchema);
+ selectOperation.setColumns(hwvtepTableColumn);;
+
+ ArrayList<Operation> operations = new ArrayList<Operation>();
+ operations.add(selectOperation);
+ operations.add(op.comment("Fetching hardware_vtep table rows"));
+
+ List<OperationResult> results = null;
+ try {
+ results = connectionInstance.transact(dbSchema, operations).get();
+ if (results != null ) {
+ OperationResult selectResult = results.get(0);
+ globalRow = TyperUtils.getTypedRowWrapper(
+ dbSchema,Global.class,selectResult.getRows().get(0));
+ }
+ } catch (InterruptedException | ExecutionException e) {
+ LOG.warn("Not able to fetch hardware_vtep table row from device {}",
+ connectionInstance.getConnectionInfo(),e);
+ }
+ }
+ LOG.trace("Fetched global {} from hardware_vtep schema",globalRow);
+ return globalRow;
+ }
+
+ private Entity getEntityFromConnectionInstance(@Nonnull HwvtepConnectionInstance hwvtepConnectionInstance) {
+ YangInstanceIdentifier entityId = null;
+ InstanceIdentifier<Node> iid = hwvtepConnectionInstance.getInstanceIdentifier();;
+ if ( iid == null ) {
+ //TODO: Is Global the right one?
+ Global hwvtepGlobalRow = getHwvtepGlobalTableEntry(hwvtepConnectionInstance);
+ iid = HwvtepSouthboundMapper.getInstanceIdentifier(hwvtepGlobalRow);
+ LOG.info("InstanceIdentifier {} generated for device "
+ + "connection {}",iid, hwvtepConnectionInstance.getConnectionInfo());
+
+ }
+ entityId = HwvtepSouthboundUtil.getInstanceIdentifierCodec().getYangInstanceIdentifier(iid);
+ Entity deviceEntity = new Entity(ENTITY_TYPE, entityId);
+ LOG.debug("Entity {} created for device connection {}",
+ deviceEntity, hwvtepConnectionInstance.getConnectionInfo());
+ return deviceEntity;
+ }
+ private void unregisterEntityForOwnership(HwvtepConnectionInstance hwvtepConnectionInstance) {
+ hwvtepConnectionInstance.closeDeviceOwnershipCandidateRegistration();
+ entityConnectionMap.remove(hwvtepConnectionInstance.getConnectedEntity());
+ }
+
+ public void handleOwnershipChanged(EntityOwnershipChange ownershipChange) {
+ HwvtepConnectionInstance hwvtepConnectionInstance = getConnectionInstanceFromEntity(ownershipChange.getEntity());
+ LOG.info("handleOwnershipChanged: {} event received for device {}",
+ ownershipChange, hwvtepConnectionInstance != null ? hwvtepConnectionInstance.getConnectionInfo()
+ : "THAT'S NOT REGISTERED BY THIS SOUTHBOUND PLUGIN INSTANCE");
+
+ if (hwvtepConnectionInstance == null) {
+ if (ownershipChange.isOwner()) {
+ LOG.warn("handleOwnershipChanged: found no connection instance for {}", ownershipChange.getEntity());
+ } else {
+ // EntityOwnershipService sends notification to all the nodes, irrespective of whether
+ // that instance registered for the device ownership or not. It is to make sure that
+ // If all the controller instance that was connected to the device are down, so the
+ // running instance can clear up the operational data store even though it was not
+ // connected to the device.
+ LOG.debug("handleOwnershipChanged: found no connection instance for {}", ownershipChange.getEntity());
+ }
+
+ // If entity has no owner, clean up the operational data store (it's possible because owner controller
+ // might went down abruptly and didn't get a chance to clean up the operational data store.
+ if (!ownershipChange.hasOwner()) {
+ LOG.debug("{} has no onwer, cleaning up the operational data store", ownershipChange.getEntity());
+ // Below code might look weird but it's required. We want to give first opportunity to the
+ // previous owner of the device to clean up the operational data store if there is no owner now.
+ // That way we will avoid lot of nasty md-sal exceptions because of concurrent delete.
+ if (ownershipChange.wasOwner()) {
+ cleanEntityOperationalData(ownershipChange.getEntity());
+ }
+ // If first cleanEntityOperationalData() was called, this call will be no-op.
+ cleanEntityOperationalData(ownershipChange.getEntity());
+ }
+ return;
+ }
+ //Connection detail need to be cached, irrespective of ownership result.
+ putConnectionInstance(hwvtepConnectionInstance.getMDConnectionInfo(),hwvtepConnectionInstance);
+
+ if (ownershipChange.isOwner() == hwvtepConnectionInstance.getHasDeviceOwnership()) {
+ LOG.debug("handleOwnershipChanged: no change in ownership for {}. Ownership status is : {}",
+ hwvtepConnectionInstance.getConnectionInfo(), hwvtepConnectionInstance.getHasDeviceOwnership());
+ return;
+ }
+
+ hwvtepConnectionInstance.setHasDeviceOwnership(ownershipChange.isOwner());
+ // You were not an owner, but now you are
+ if (ownershipChange.isOwner()) {
+ LOG.info("handleOwnershipChanged: *this* southbound plugin instance is owner of device {}",
+ hwvtepConnectionInstance.getConnectionInfo());
+
+ //*this* instance of southbound plugin is owner of the device,
+ //so register for monitor callbacks
+ hwvtepConnectionInstance.registerCallbacks();
+
+ } else {
+ //You were owner of the device, but now you are not. With the current ownership
+ //grant mechanism, this scenario should not occur. Because this scenario will occur
+ //when this controller went down or switch flap the connection, but in both the case
+ //it will go through the re-registration process. We need to implement this condition
+ //when clustering service implement a ownership grant strategy which can revoke the
+ //device ownership for load balancing the devices across the instances.
+ //Once this condition occur, we should unregister the callback.
+ LOG.error("handleOwnershipChanged: *this* southbound plugin instance is no longer the owner of device {}",
+ hwvtepConnectionInstance.getNodeId().getValue());
+ }
+ }
+
+ private void cleanEntityOperationalData(Entity entity) {
+ //TODO: remove entity from Operational DataStore
+ LOG.error("cleanEntityOperationalData(): Code incomplete");
+ }
+
+ private HwvtepConnectionInstance getConnectionInstanceFromEntity(Entity entity) {
+ return entityConnectionMap.get(entity);
+ }
+
+ private class HwvtepDeviceEntityOwnershipListener implements EntityOwnershipListener {
+ private HwvtepConnectionManager hcm;
+ private EntityOwnershipListenerRegistration listenerRegistration;
+
+ HwvtepDeviceEntityOwnershipListener(HwvtepConnectionManager hcm, EntityOwnershipService entityOwnershipService) {
+ this.hcm = hcm;
+ listenerRegistration = entityOwnershipService.registerListener(ENTITY_TYPE, this);
+ }
+ public void close() {
+ listenerRegistration.close();
+ }
+ @Override
+ public void ownershipChanged(EntityOwnershipChange ownershipChange) {
+ hcm.handleOwnershipChanged(ownershipChange);
+ }
+ }
+
+}
--- /dev/null
+/*
+ * Copyright (c) 2015 Ericsson India Global Services Pvt Ltd. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.ovsdb.hwvtepsouthbound;
+
+import org.opendaylight.ovsdb.hwvtepsouthbound.transactions.md.HwvtepOperationalCommandAggregator;
+import org.opendaylight.ovsdb.hwvtepsouthbound.transactions.md.TransactionInvoker;
+import org.opendaylight.ovsdb.lib.MonitorCallBack;
+import org.opendaylight.ovsdb.lib.message.TableUpdates;
+import org.opendaylight.ovsdb.lib.schema.DatabaseSchema;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class HwvtepMonitorCallback implements MonitorCallBack {
+
+ private static final Logger LOG = LoggerFactory.getLogger(HwvtepMonitorCallback.class);
+ private HwvtepConnectionInstance key;
+ private TransactionInvoker txInvoker;
+
+ HwvtepMonitorCallback(HwvtepConnectionInstance key,TransactionInvoker txInvoker) {
+ this.txInvoker = txInvoker;
+ this.key = key;
+ }
+
+ @Override
+ public void update(TableUpdates result, DatabaseSchema dbSchema) {
+ LOG.debug("result: {} dbSchema: {}",result,dbSchema);
+ txInvoker.invoke(new HwvtepOperationalCommandAggregator(key, result, dbSchema));
+ LOG.trace("update exit");
+ }
+
+ @Override
+ public void exception(Throwable exception) {
+ LOG.warn("exception {}", exception);
+ }
+
+}
--- /dev/null
+/*
+ * Copyright (c) 2015 Ericsson India Global Services Pvt Ltd. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.ovsdb.hwvtepsouthbound;
+
+public class HwvtepSchemaConstants {
+ public static final String databaseName = "hardware_vtep";
+ public enum HWVTEPSCHEMATABLES {
+ GLOBAL("Global", null, null),
+ MANAGER("Manager","Global","managers"),
+ PHYSICALSWITCH("Physical_Switch","Global","switches"),
+ PHYSICALPORT("Physical_Port","Physical_Switch","ports"),
+ TUNNEL("Tunnel","Physical_Switch","tunnels"),
+ LOGICALSWITCH("Logical_Switch","Physical_Port","vlan_bindings"),
+ ACL("ACL","Physical_Port","acl_bindings"),
+ LOGICALBINDINGSTATS("Logical_Binding_Stats","Physical_Port","vlan_stats"),
+// PHYSICALLOCATORLOCAL("Physical_Locator","Tunnel","local"),
+// PHYSICALLOCATORREMOTE("Physical_Locator","Tunnel","remote"),
+ UCASTMACSLOCAL("Ucast_Macs_Local",null, null),
+ UCASTMACSREMOTE("Ucast_Macs_Remote",null, null),
+ MCASTMACSLOCAL("Mcast_Macs_Local",null, null),
+ PHYSICALLOCATORSET("Physical_Locator_Set","Mcast_Macs_Local", "locator_set"),
+ MCASTMACSREMOTE("Mcast_Macs_Remote",null, null),
+ LOGICALROUTER("Logical_Router",null, null),
+ ARPSOURCESLOCAL("Arp_Sources_Local",null, null),
+ ARPSOURCESREMOTE("Arp_Sources_Remote",null, null),
+ PHYSICALLOCATOR("Physical_Locator","Physical_Locator_Set", "locators"),
+ ACLENTRY("Acl_Entry","ACL", "acl_entries");
+
+ private final String tableName;
+ private final String parentTableName;
+ private final String columnNameInParentTable;
+
+ private HWVTEPSCHEMATABLES(final String tableName, final String parentTableName,
+ final String columnNameInParentTable) {
+ this.tableName = tableName;
+ this.parentTableName = parentTableName;
+ this.columnNameInParentTable = columnNameInParentTable;
+ }
+
+ public String getTableName() {
+ return this.tableName;
+ }
+
+ public String getParentTableName() {
+ return this.parentTableName;
+ }
+
+ public String getColumnNameInParentTable() {
+ return this.columnNameInParentTable;
+ }
+ }
+
+}
--- /dev/null
+/*
+ * Copyright (c) 2015 Ericsson India Global Services Pvt Ltd. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.ovsdb.hwvtepsouthbound;
+
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Uri;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.TopologyId;
+
+public class HwvtepSouthboundConstants {
+
+ public static final TopologyId HWVTEP_TOPOLOGY_ID = new TopologyId(new Uri("hwvtep:1"));
+ public static final String HWVTEP_URI_PREFIX = "hwvtep";
+ public static final Integer DEFAULT_OVSDB_PORT = 6640;
+ public static final String IID_OTHER_CONFIG_KEY = "opendaylight-iid";
+ public static final String UUID = "uuid";
+}
--- /dev/null
+/*
+ * Copyright (c) 2015 Ericsson India Global Services Pvt Ltd. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.ovsdb.hwvtepsouthbound;
+
+import java.net.Inet4Address;
+import java.net.Inet6Address;
+import java.net.InetAddress;
+import org.opendaylight.ovsdb.lib.OvsdbClient;
+import org.opendaylight.ovsdb.schema.hardwarevtep.Global;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IpAddress;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Ipv4Address;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Ipv6Address;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.PortNumber;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Uri;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.global.attributes.ConnectionInfo;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.global.attributes.ConnectionInfoBuilder;
+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.NodeId;
+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.Node;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.NodeKey;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class HwvtepSouthboundMapper {
+ private static final Logger LOG = LoggerFactory.getLogger(HwvtepSouthboundMapper.class);
+ private static final String N_CONNECTIONS_STR = "n_connections";
+
+ private static NodeId createNodeId(HwvtepConnectionInstance client) {
+ NodeKey key = client.getInstanceIdentifier().firstKeyOf(Node.class, NodeKey.class);
+ return key.getNodeId();
+
+ }
+
+ public static InstanceIdentifier<Node> createInstanceIdentifier(NodeId nodeId) {
+ InstanceIdentifier<Node> nodePath = InstanceIdentifier
+ .create(NetworkTopology.class)
+ .child(Topology.class, new TopologyKey(HwvtepSouthboundConstants.HWVTEP_TOPOLOGY_ID))
+ .child(Node.class,new NodeKey(nodeId));
+ return nodePath;
+ }
+
+ public static InstanceIdentifier<Node> createInstanceIdentifier (OvsdbClient client) {
+ return createInstanceIdentifier(createIpAddress(client.getConnectionInfo().getRemoteAddress()),
+ new PortNumber(client.getConnectionInfo().getRemotePort()));
+ }
+
+ private static InstanceIdentifier<Node> createInstanceIdentifier(IpAddress ip, PortNumber port) {
+ String uriString = HwvtepSouthboundConstants.HWVTEP_URI_PREFIX + "://"
+ + new String(ip.getValue()) + ":" + port.getValue();
+ Uri uri = new Uri(uriString);
+ NodeId nodeId = new NodeId(uri);
+ InstanceIdentifier<Node> path = InstanceIdentifier.create(NetworkTopology.class)
+ .child(Topology.class, new TopologyKey(HwvtepSouthboundConstants.HWVTEP_TOPOLOGY_ID))
+ .child(Node.class,new NodeKey(nodeId));
+ LOG.debug("Created ovsdb path: {}",path);
+ return path;
+ }
+
+ public static NodeId createManagedNodeId(InstanceIdentifier<Node> iid) {
+ NodeKey nodeKey = iid.firstKeyOf(Node.class, NodeKey.class);
+ return nodeKey.getNodeId();
+ }
+
+ public static IpAddress createIpAddress(InetAddress address) {
+ IpAddress ip = null;
+ if (address instanceof Inet4Address) {
+ ip = createIpAddress((Inet4Address)address);
+ } else if (address instanceof Inet6Address) {
+ ip = createIpAddress((Inet6Address)address);
+ }
+ return ip;
+ }
+
+ public static IpAddress createIpAddress(Inet4Address address) {
+ Ipv4Address ipv4 = new Ipv4Address(address.getHostAddress());
+ return new IpAddress(ipv4);
+ }
+
+ public static IpAddress createIpAddress(Inet6Address address) {
+ Ipv6Address ipv6 = new Ipv6Address(address.getHostAddress());
+ return new IpAddress(ipv6);
+ }
+
+ public static ConnectionInfo createConnectionInfo(OvsdbClient client) {
+ ConnectionInfoBuilder connectionInfoBuilder = new ConnectionInfoBuilder();
+ connectionInfoBuilder.setRemoteIp(createIpAddress(client.getConnectionInfo().getRemoteAddress()));
+ connectionInfoBuilder.setRemotePort(new PortNumber(client.getConnectionInfo().getRemotePort()));
+ connectionInfoBuilder.setLocalIp(createIpAddress(client.getConnectionInfo().getLocalAddress()));
+ connectionInfoBuilder.setLocalPort(new PortNumber(client.getConnectionInfo().getLocalPort()));
+ return connectionInfoBuilder.build();
+ }
+
+ public static ConnectionInfo suppressLocalIpPort(ConnectionInfo connectionInfo) {
+ ConnectionInfoBuilder connectionInfoBuilder = new ConnectionInfoBuilder();
+ connectionInfoBuilder.setRemoteIp(connectionInfo.getRemoteIp());
+ connectionInfoBuilder.setRemotePort(connectionInfo.getRemotePort());
+ return connectionInfoBuilder.build();
+ }
+
+ public static InstanceIdentifier<Node> getInstanceIdentifier(Global global) {
+ InstanceIdentifier<Node> iid = null;
+ if (global.getManagersColumn() != null
+ && global.getManagersColumn().getData() != null) {
+ String iidString = global.getManagersColumn().getData().iterator().next().toString();
+ iid = (InstanceIdentifier<Node>) HwvtepSouthboundUtil.deserializeInstanceIdentifier(iidString);
+ } else {
+ String nodeString = HwvtepSouthboundConstants.HWVTEP_URI_PREFIX + "://" +
+ HwvtepSouthboundConstants.UUID + "/" + global.getUuid().toString();
+ NodeId nodeId = new NodeId(new Uri(nodeString));
+ NodeKey nodeKey = new NodeKey(nodeId);
+ TopologyKey topoKey = new TopologyKey(HwvtepSouthboundConstants.HWVTEP_TOPOLOGY_ID);
+ iid = InstanceIdentifier.builder(NetworkTopology.class)
+ .child(Topology.class, topoKey)
+ .child(Node.class,nodeKey)
+ .build();
+ }
+ return iid;
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2015 Ericsson India Global Services Pvt Ltd. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.ovsdb.hwvtepsouthbound;
+
+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.clustering.CandidateAlreadyRegisteredException;
+import org.opendaylight.controller.md.sal.common.api.clustering.Entity;
+import org.opendaylight.controller.md.sal.common.api.clustering.EntityOwnershipCandidateRegistration;
+import org.opendaylight.controller.md.sal.common.api.clustering.EntityOwnershipChange;
+import org.opendaylight.controller.md.sal.common.api.clustering.EntityOwnershipListener;
+import org.opendaylight.controller.md.sal.common.api.clustering.EntityOwnershipListenerRegistration;
+import org.opendaylight.controller.md.sal.common.api.clustering.EntityOwnershipService;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException;
+import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ProviderContext;
+import org.opendaylight.controller.sal.binding.api.BindingAwareProvider;
+import org.opendaylight.ovsdb.hwvtepsouthbound.transactions.md.TransactionInvoker;
+import org.opendaylight.ovsdb.hwvtepsouthbound.transactions.md.TransactionInvokerImpl;
+import org.opendaylight.ovsdb.lib.OvsdbConnection;
+import org.opendaylight.ovsdb.lib.impl.OvsdbConnectionService;
+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.NetworkTopologyBuilder;
+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.TopologyBuilder;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.TopologyKey;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.base.Optional;
+import com.google.common.util.concurrent.CheckedFuture;
+
+public class HwvtepSouthboundProvider implements BindingAwareProvider, AutoCloseable {
+
+ private static final Logger LOG = LoggerFactory.getLogger(HwvtepSouthboundProvider.class);
+ private static final String ENTITY_TYPE = "ovsdb-hwvtepsouthbound-provider";
+
+ public static DataBroker getDb() {
+ return db;
+ }
+
+ private static DataBroker db;
+ private HwvtepConnectionManager cm;
+ private OvsdbConnection ovsdbConnection;
+ private TransactionInvoker txInvoker;
+ private EntityOwnershipService entityOwnershipService;
+ private EntityOwnershipCandidateRegistration registration;
+ private HwvtepsbPluginInstanceEntityOwnershipListener providerOwnershipChangeListener;
+
+ public HwvtepSouthboundProvider(
+ EntityOwnershipService entityOwnershipServiceDependency) {
+ this.entityOwnershipService = entityOwnershipServiceDependency;
+ registration = null;
+ }
+
+ @Override
+ public void onSessionInitiated(ProviderContext session) {
+ LOG.info("HwvtepSouthboundProvider Session Initiated");
+ db = session.getSALService(DataBroker.class);
+ txInvoker = new TransactionInvokerImpl(db);
+ cm = new HwvtepConnectionManager(db, txInvoker, entityOwnershipService);
+ //TODO: Add DataChange Listener
+
+ //Register listener for entityOnwership changes
+ providerOwnershipChangeListener =
+ new HwvtepsbPluginInstanceEntityOwnershipListener(this,this.entityOwnershipService);
+ entityOwnershipService.registerListener(ENTITY_TYPE,providerOwnershipChangeListener);
+
+ //register instance entity to get the ownership of the provider
+ Entity instanceEntity = new Entity(ENTITY_TYPE, ENTITY_TYPE);
+ try {
+ registration = entityOwnershipService.registerCandidate(instanceEntity);
+ } catch (CandidateAlreadyRegisteredException e) {
+ LOG.warn("HWVTEP Southbound Provider instance entity {} was already "
+ + "registered for {} ownership", instanceEntity, e);
+ }
+ }
+
+ @Override
+ public void close() throws Exception {
+ LOG.info("HwvtepSouthboundProvider Closed");
+ if(cm != null){
+ cm.close();
+ cm = null;
+ }
+ if(registration != null) {
+ registration.close();
+ registration = null;
+ }
+ if(providerOwnershipChangeListener != null) {
+ providerOwnershipChangeListener.close();
+ providerOwnershipChangeListener = null;
+ }
+ }
+
+ private void initializeHwvtepTopology(LogicalDatastoreType type) {
+ InstanceIdentifier<Topology> path = InstanceIdentifier
+ .create(NetworkTopology.class)
+ .child(Topology.class, new TopologyKey(HwvtepSouthboundConstants.HWVTEP_TOPOLOGY_ID));
+ initializeTopology(type);
+ ReadWriteTransaction transaction = db.newReadWriteTransaction();
+ CheckedFuture<Optional<Topology>, ReadFailedException> hwvtepTp = transaction.read(type, path);
+ try {
+ if (!hwvtepTp.get().isPresent()) {
+ TopologyBuilder tpb = new TopologyBuilder();
+ tpb.setTopologyId(HwvtepSouthboundConstants.HWVTEP_TOPOLOGY_ID);
+ transaction.put(type, path, tpb.build());
+ transaction.submit();
+ } else {
+ transaction.cancel();
+ }
+ } catch (Exception e) {
+ LOG.error("Error initializing hwvtep topology", e);
+ }
+ }
+
+ private void initializeTopology(LogicalDatastoreType type) {
+ ReadWriteTransaction transaction = db.newReadWriteTransaction();
+ InstanceIdentifier<NetworkTopology> path = InstanceIdentifier.create(NetworkTopology.class);
+ CheckedFuture<Optional<NetworkTopology>, ReadFailedException> topology = transaction.read(type,path);
+ try {
+ if (!topology.get().isPresent()) {
+ NetworkTopologyBuilder ntb = new NetworkTopologyBuilder();
+ transaction.put(type,path,ntb.build());
+ transaction.submit();
+ } else {
+ transaction.cancel();
+ }
+ } catch (Exception e) {
+ LOG.error("Error initializing hwvtep topology {}",e);
+ }
+ }
+
+ public void handleOwnershipChange(EntityOwnershipChange ownershipChange) {
+ if (ownershipChange.isOwner()) {
+ LOG.info("*This* instance of HWVTEP southbound provider is set as a MASTER instance");
+ LOG.info("Initialize HWVTEP topology {} in operational and config data store if not already present"
+ ,HwvtepSouthboundConstants.HWVTEP_TOPOLOGY_ID);
+ initializeHwvtepTopology(LogicalDatastoreType.OPERATIONAL);
+ initializeHwvtepTopology(LogicalDatastoreType.CONFIGURATION);
+ } else {
+ LOG.info("*This* instance of HWVTEP southbound provider is set as a SLAVE instance");
+ }
+ //TODO: How to make this co-exist with OvsdbSouthbound?
+ if (ovsdbConnection == null) {
+ ovsdbConnection = new OvsdbConnectionService();
+ ovsdbConnection.registerConnectionListener(cm);
+ ovsdbConnection.startOvsdbManager(HwvtepSouthboundConstants.DEFAULT_OVSDB_PORT);
+ }
+ }
+
+ private class HwvtepsbPluginInstanceEntityOwnershipListener implements EntityOwnershipListener {
+ private HwvtepSouthboundProvider hsp;
+ private EntityOwnershipListenerRegistration listenerRegistration;
+
+ HwvtepsbPluginInstanceEntityOwnershipListener(HwvtepSouthboundProvider hsp,
+ EntityOwnershipService entityOwnershipService) {
+ this.hsp = hsp;
+ listenerRegistration = entityOwnershipService.registerListener(ENTITY_TYPE, this);
+ }
+
+ public void close() {
+ this.listenerRegistration.close();
+ }
+ @Override
+ public void ownershipChanged(EntityOwnershipChange ownershipChange) {
+ hsp.handleOwnershipChange(ownershipChange);
+ }
+ }
+
+}
--- /dev/null
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.ovsdb.hwvtepsouthbound;
+
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.impl.codec.DeserializationException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class HwvtepSouthboundUtil {
+
+ private static final Logger LOG = LoggerFactory.getLogger(HwvtepSouthboundUtil.class);
+
+ private static InstanceIdentifierCodec instanceIdentifierCodec;
+
+ private HwvtepSouthboundUtil() {
+ // Prevent instantiating a utility class
+ }
+
+ public static void setInstanceIdentifierCodec(InstanceIdentifierCodec iidc) {
+ instanceIdentifierCodec = iidc;
+ }
+
+ public static InstanceIdentifierCodec getInstanceIdentifierCodec() {
+ return instanceIdentifierCodec;
+ }
+
+ public static String serializeInstanceIdentifier(InstanceIdentifier<?> iid) {
+ return instanceIdentifierCodec.serialize(iid);
+ }
+
+ public static InstanceIdentifier<?> deserializeInstanceIdentifier(String iidString) {
+ InstanceIdentifier<?> result = null;
+ try {
+ result = instanceIdentifierCodec.bindingDeserializer(iidString);
+ } catch (DeserializationException e) {
+ LOG.warn("Unable to deserialize iidString", e);
+ }
+ return result;
+ }
+
+
+}
--- /dev/null
+/*
+ * Copyright (c) 2015 Ericsson India Global Services Pvt Ltd. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.ovsdb.hwvtepsouthbound;
+
+import java.net.URI;
+
+import org.opendaylight.controller.sal.core.api.model.SchemaService;
+import org.opendaylight.yangtools.binding.data.codec.api.BindingNormalizedNodeSerializer;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.impl.codec.DeserializationException;
+import org.opendaylight.yangtools.yang.data.util.AbstractModuleStringInstanceIdentifierCodec;
+import org.opendaylight.yangtools.yang.data.util.DataSchemaContextTree;
+import org.opendaylight.yangtools.yang.model.api.Module;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+import org.opendaylight.yangtools.yang.model.api.SchemaContextListener;
+
+public class InstanceIdentifierCodec extends AbstractModuleStringInstanceIdentifierCodec
+ implements SchemaContextListener {
+
+ private DataSchemaContextTree dataSchemaContextTree;
+ private SchemaContext context;
+ private BindingNormalizedNodeSerializer bindingNormalizedNodeSerializer;
+
+ public InstanceIdentifierCodec(SchemaService schemaService,
+ BindingNormalizedNodeSerializer bindingNormalizedNodeSerializer) {
+ schemaService.registerSchemaContextListener(this);
+ this.bindingNormalizedNodeSerializer = bindingNormalizedNodeSerializer;
+ }
+
+ @Override
+ protected DataSchemaContextTree getDataContextTree() {
+ return dataSchemaContextTree;
+ }
+
+ @Override
+ protected Module moduleForPrefix(final String prefix) {
+ return context.findModuleByName(prefix, null);
+ }
+
+ @Override
+ protected String prefixForNamespace(final URI namespace) {
+ final Module module = context.findModuleByNamespaceAndRevision(namespace, null);
+ return module == null ? null : module.getName();
+ }
+
+ @Override
+ public void onGlobalContextUpdated(SchemaContext context) {
+ this.context = context;
+ this.dataSchemaContextTree = DataSchemaContextTree.from(context);
+ }
+
+ public String serialize(InstanceIdentifier<?> iid) {
+ YangInstanceIdentifier normalizedIid = bindingNormalizedNodeSerializer.toYangInstanceIdentifier(iid);
+ return serialize(normalizedIid);
+ }
+
+ public YangInstanceIdentifier getYangInstanceIdentifier(InstanceIdentifier<?> iid) {
+ return bindingNormalizedNodeSerializer.toYangInstanceIdentifier(iid);
+ }
+
+ public InstanceIdentifier<?> bindingDeserializer(String iidString) throws DeserializationException {
+ YangInstanceIdentifier normalizedYangIid = deserialize(iidString);
+ InstanceIdentifier<?> iid = bindingNormalizedNodeSerializer.fromYangInstanceIdentifier(normalizedYangIid);
+ return iid;
+ }
+
+ public InstanceIdentifier<?> bindingDeserializer(YangInstanceIdentifier yangIID) {
+ InstanceIdentifier<?> iid = bindingNormalizedNodeSerializer.fromYangInstanceIdentifier(yangIID);
+ return iid;
+ }
+}
+++ /dev/null
-/*
- * Copyright (c) 2015 Ericsson India Global Services Pvt Ltd. and others. All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-package org.opendaylight.ovsdb.hwvtepsouthbound.impl;
-
-import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ProviderContext;
-import org.opendaylight.controller.sal.binding.api.BindingAwareProvider;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-public class HwvtepSouthboundProvider implements BindingAwareProvider, AutoCloseable {
-
- private static final Logger LOG = LoggerFactory.getLogger(HwvtepSouthboundProvider.class);
-
- @Override
- public void onSessionInitiated(ProviderContext session) {
- LOG.info("HwvtepSouthboundProvider Session Initiated");
- }
-
- @Override
- public void close() throws Exception {
- LOG.info("HwvtepSouthboundProvider Closed");
- }
-
-}
--- /dev/null
+/*
+ * Copyright (c) 2015 Ericsson India Global Services Pvt Ltd. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.ovsdb.hwvtepsouthbound.transact;
+
+import org.opendaylight.ovsdb.lib.operations.TransactionBuilder;
+
+public interface TransactCommand {
+
+ void execute(TransactionBuilder transaction);
+
+}
--- /dev/null
+/*
+ * Copyright (c) 2015 Ericsson India Global Services Pvt Ltd. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.ovsdb.hwvtepsouthbound.transact;
+
+public interface TransactInvoker {
+ void invoke(TransactCommand command);
+}
--- /dev/null
+/*
+ * Copyright (c) 2015 Ericsson India Global Services Pvt Ltd. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.ovsdb.hwvtepsouthbound.transact;
+
+import java.util.List;
+
+import org.opendaylight.ovsdb.hwvtepsouthbound.HwvtepConnectionInstance;
+import org.opendaylight.ovsdb.lib.operations.OperationResult;
+import org.opendaylight.ovsdb.lib.operations.TransactionBuilder;
+import org.opendaylight.ovsdb.lib.schema.DatabaseSchema;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.util.concurrent.ListenableFuture;
+
+public class TransactInvokerImpl implements TransactInvoker {
+ private static final Logger LOG = LoggerFactory.getLogger(TransactInvokerImpl.class);
+ private HwvtepConnectionInstance connectionInstance;
+ private DatabaseSchema dbSchema;
+
+ public TransactInvokerImpl(HwvtepConnectionInstance connectionInstance, DatabaseSchema dbSchema) {
+ this.connectionInstance = connectionInstance;
+ this.dbSchema = dbSchema;
+ }
+
+ @Override
+ public void invoke(TransactCommand command) {
+ TransactionBuilder tb = new TransactionBuilder(connectionInstance, dbSchema);
+ command.execute(tb);
+ ListenableFuture<List<OperationResult>> result = tb.execute();
+ LOG.debug("invoke: command: {}, tb: {}", command, tb);
+ if (tb.getOperations().size() > 0) {
+ try {
+ List<OperationResult> got = result.get();
+ LOG.debug("OVSDB transaction result: {}", got);
+ } catch (Exception e) {
+ LOG.warn("Transact execution exception: ", e);
+ }
+ LOG.trace("invoke exit command: {}, tb: {}", command, tb);
+ }
+ }
+
+}
--- /dev/null
+/*
+ * Copyright (c) 2015 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.ovsdb.hwvtepsouthbound.transactions.md;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction;
+import org.opendaylight.ovsdb.hwvtepsouthbound.HwvtepConnectionInstance;
+import org.opendaylight.ovsdb.lib.message.TableUpdates;
+import org.opendaylight.ovsdb.lib.schema.DatabaseSchema;
+
+public class HwvtepOperationalCommandAggregator implements TransactionCommand {
+
+
+ private List<TransactionCommand> commands = new ArrayList<TransactionCommand>();
+
+ public HwvtepOperationalCommandAggregator(HwvtepConnectionInstance key,TableUpdates updates,
+ DatabaseSchema dbSchema) {
+ //TODO: Add commands in here
+ }
+
+ @Override
+ public void execute(ReadWriteTransaction transaction) {
+ for (TransactionCommand command: commands) {
+ command.execute(transaction);
+ }
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2015 Ericsson India Global Services Pvt Ltd. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.ovsdb.hwvtepsouthbound.transactions.md;
+
+import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction;
+
+public interface TransactionCommand {
+
+ void execute(ReadWriteTransaction transaction);
+
+}
\ No newline at end of file
--- /dev/null
+/*
+ * Copyright (c) 2015 Ericsson India Global Services Pvt Ltd. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.ovsdb.hwvtepsouthbound.transactions.md;
+
+public interface TransactionInvoker {
+
+ void invoke(TransactionCommand command);
+
+}
--- /dev/null
+/*
+ * Copyright (c) 2015 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.ovsdb.hwvtepsouthbound.transactions.md;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.ThreadFactory;
+
+import org.opendaylight.controller.md.sal.binding.api.BindingTransactionChain;
+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.AsyncTransaction;
+import org.opendaylight.controller.md.sal.common.api.data.TransactionChain;
+import org.opendaylight.controller.md.sal.common.api.data.TransactionChainListener;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.util.concurrent.FutureCallback;
+import com.google.common.util.concurrent.Futures;
+import com.google.common.util.concurrent.ThreadFactoryBuilder;
+
+/* TODO:
+ * Copied over as-is from southbound plugin. Good candidate to be common
+ * when refactoring code.
+ */
+public class TransactionInvokerImpl implements TransactionInvoker,TransactionChainListener, Runnable, AutoCloseable {
+ private static final Logger LOG = LoggerFactory.getLogger(TransactionInvokerImpl.class);
+ private static final int QUEUE_SIZE = 10000;
+ private BindingTransactionChain chain;
+ private DataBroker db;
+ private BlockingQueue<TransactionCommand> inputQueue = new LinkedBlockingQueue<TransactionCommand>(QUEUE_SIZE);
+ private BlockingQueue<ReadWriteTransaction> successfulTransactionQueue
+ = new LinkedBlockingQueue<ReadWriteTransaction>(QUEUE_SIZE);
+ private BlockingQueue<AsyncTransaction<?, ?>> failedTransactionQueue
+ = new LinkedBlockingQueue<AsyncTransaction<?, ?>>(QUEUE_SIZE);
+ private ExecutorService executor;
+ private Map<ReadWriteTransaction,TransactionCommand> transactionToCommand
+ = new HashMap<ReadWriteTransaction,TransactionCommand>();
+ private List<ReadWriteTransaction> pendingTransactions = new ArrayList<ReadWriteTransaction>();
+
+ public TransactionInvokerImpl(DataBroker db) {
+ this.db = db;
+ this.chain = db.createTransactionChain(this);
+ ThreadFactory threadFact = new ThreadFactoryBuilder().setNameFormat("transaction-invoker-impl-%d").build();
+ executor = Executors.newSingleThreadExecutor(threadFact);
+ executor.submit(this);
+ }
+
+ @Override
+ public void invoke(final TransactionCommand command) {
+ // TODO what do we do if queue is full?
+ inputQueue.offer(command);
+ }
+
+ @Override
+ public void onTransactionChainFailed(TransactionChain<?, ?> chain,
+ AsyncTransaction<?, ?> transaction, Throwable cause) {
+ failedTransactionQueue.offer(transaction);
+ }
+
+ @Override
+ public void onTransactionChainSuccessful(TransactionChain<?, ?> chain) {
+ // NO OP
+
+ }
+
+ @Override
+ public void run() {
+ while (true) {
+ forgetSuccessfulTransactions();
+ try {
+ List<TransactionCommand> commands = extractCommands();
+ for (TransactionCommand command: commands) {
+ final ReadWriteTransaction transaction = chain.newReadWriteTransaction();
+ recordPendingTransaction(command, transaction);
+ command.execute(transaction);
+ Futures.addCallback(transaction.submit(), new FutureCallback<Void>() {
+ @Override
+ public void onSuccess(final Void result) {
+ successfulTransactionQueue.offer(transaction);
+ }
+
+ @Override
+ public void onFailure(final Throwable throwable) {
+ // NOOP - handled by failure of transaction chain
+ }
+ });
+ }
+ } catch (Exception e) {
+ LOG.warn("Exception invoking Transaction: ", e);
+ }
+ }
+ }
+
+ private List<TransactionCommand> extractResubmitCommands() {
+ AsyncTransaction<?, ?> transaction = failedTransactionQueue.poll();
+ List<TransactionCommand> commands = new ArrayList<TransactionCommand>();
+ if (transaction != null) {
+ int index = pendingTransactions.lastIndexOf(transaction);
+ List<ReadWriteTransaction> transactions =
+ pendingTransactions.subList(index, pendingTransactions.size() - 1);
+ for (ReadWriteTransaction tx: transactions) {
+ commands.add(transactionToCommand.get(tx));
+ }
+ resetTransactionQueue();
+ }
+ return commands;
+ }
+
+ private void resetTransactionQueue() {
+ chain.close();
+ chain = db.createTransactionChain(this);
+ pendingTransactions = new ArrayList<ReadWriteTransaction>();
+ transactionToCommand = new HashMap<ReadWriteTransaction,TransactionCommand>();
+ failedTransactionQueue.clear();
+ successfulTransactionQueue.clear();
+ }
+
+ private void recordPendingTransaction(TransactionCommand command,
+ final ReadWriteTransaction transaction) {
+ transactionToCommand.put(transaction, command);
+ pendingTransactions.add(transaction);
+ }
+
+ private List<TransactionCommand> extractCommands() throws InterruptedException {
+ List<TransactionCommand> commands = extractResubmitCommands();
+ commands.addAll(extractCommandsFromQueue());
+ return commands;
+ }
+
+ private List<TransactionCommand> extractCommandsFromQueue() throws InterruptedException {
+ List<TransactionCommand> result = new ArrayList<TransactionCommand>();
+ TransactionCommand command = inputQueue.take();
+ while (command != null) {
+ result.add(command);
+ command = inputQueue.poll();
+ }
+ return result;
+ }
+
+ private void forgetSuccessfulTransactions() {
+ ReadWriteTransaction transaction = successfulTransactionQueue.poll();
+ while (transaction != null) {
+ pendingTransactions.remove(transaction);
+ transactionToCommand.remove(transaction);
+ transaction = successfulTransactionQueue.poll();
+ }
+ }
+
+ @Override
+ public void close() throws Exception {
+ this.executor.shutdown();
+ }
+}
package org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hwvtepsouthbound.impl.rev150901;
-import org.opendaylight.ovsdb.hwvtepsouthbound.impl.HwvtepSouthboundProvider;
+import org.opendaylight.ovsdb.hwvtepsouthbound.HwvtepSouthboundProvider;
+import org.opendaylight.ovsdb.hwvtepsouthbound.HwvtepSouthboundUtil;
+import org.opendaylight.ovsdb.hwvtepsouthbound.InstanceIdentifierCodec;
public class HwvtepSouthboundModule extends org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hwvtepsouthbound.impl.rev150901.AbstractHwvtepSouthboundModule {
public HwvtepSouthboundModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier, org.opendaylight.controller.config.api.DependencyResolver dependencyResolver) {
@Override
public java.lang.AutoCloseable createInstance() {
- HwvtepSouthboundProvider provider = new HwvtepSouthboundProvider();
+ HwvtepSouthboundUtil.setInstanceIdentifierCodec(new InstanceIdentifierCodec(getSchemaServiceDependency(),
+ getBindingNormalizedNodeSerializerDependency()));
+ HwvtepSouthboundProvider provider = new HwvtepSouthboundProvider(getClusteringEntityOwnershipServiceDependency());
getBrokerDependency().registerProvider(provider);
return provider;
}
import config { prefix config; revision-date 2013-04-05; }
import opendaylight-md-sal-binding { prefix md-sal-binding; revision-date 2013-10-28;}
+ import opendaylight-entity-ownership-service {prefix eos; revision-date 2015-08-10;}
+ import opendaylight-md-sal-dom {prefix dom; revision-date 2013-10-28;}
description
"Service definition for hwvtepsouthbound project";
}
}
}
+ container schema-service {
+ uses config:service-ref {
+ refine type {
+ mandatory false;
+ config:required-identity dom:schema-service;
+ }
+ }
+ }
+ container clustering-entity-ownership-service {
+ uses config:service-ref {
+ refine type {
+ mandatory true;
+ config:required-identity eos:entity-ownership-service;
+ }
+ }
+ }
+ container binding-normalized-node-serializer {
+ uses config:service-ref {
+ refine type {
+ mandatory true;
+ config:required-identity md-sal-binding:binding-normalized-node-serializer;
+ }
+ }
+ }
}
}
}
*/
package org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hwvtepsouthbound.impl.rev150901;
+import org.junit.Ignore;
import org.junit.Test;
import org.opendaylight.controller.config.api.DependencyResolver;
import org.opendaylight.controller.config.api.JmxAttribute;
import org.opendaylight.controller.config.api.ModuleIdentifier;
import org.opendaylight.controller.sal.binding.api.BindingAwareBroker;
-import org.opendaylight.ovsdb.hwvtepsouthbound.impl.HwvtepSouthboundProvider;
+import org.opendaylight.ovsdb.hwvtepsouthbound.HwvtepSouthboundProvider;
import javax.management.ObjectName;
module.customValidation();
}
+ //TODO: Ignore for now, will be replaced with better UT
+ @Ignore
@Test
public void testCreateInstance() throws Exception {
// configure mocks