import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.statistics.store.rev151215.statistics.store.StatisticRecord;
import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.statistics.store.rev151215.statistics.store.StatisticRecordKey;
import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
-import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.InstanceIdentifierBuilder;
public class IidFactory {
.build();
}
- public static InstanceIdentifier<ProviderAddressEndpointLocation> providerAddressEndpointLocationIid(String provider,
- Class<? extends AddressType> addrType, String addr, Class<? extends ContextType> cType,
+ public static InstanceIdentifier<ProviderAddressEndpointLocation> providerAddressEndpointLocationIid(
+ String provider, Class<? extends AddressType> addrType, String addr, Class<? extends ContextType> cType,
ContextId containment) {
+ return providerAddressEndpointLocationIid(new ProviderName(provider),
+ new ProviderAddressEndpointLocationKey(addr, addrType, containment, cType));
+ }
+
+ public static InstanceIdentifier<ProviderAddressEndpointLocation> providerAddressEndpointLocationIid(
+ ProviderName provider, ProviderAddressEndpointLocationKey providerAddressEndpointLocationKey) {
+ return locationProviderIid(provider).child(ProviderAddressEndpointLocation.class,
+ providerAddressEndpointLocationKey);
+ }
+
+ public static InstanceIdentifier<LocationProvider> locationProviderIid(ProviderName provider) {
return InstanceIdentifier.builder(LocationProviders.class)
- .child(LocationProvider.class, new LocationProviderKey(new ProviderName(provider)))
- .child(ProviderAddressEndpointLocation.class, new ProviderAddressEndpointLocationKey(addr, addrType, containment, cType))
+ .child(LocationProvider.class, new LocationProviderKey(provider))
.build();
}
<type>test-jar</type>
<scope>test</scope>
</dependency>
+ <dependency>
+ <groupId>org.opendaylight.groupbasedpolicy</groupId>
+ <artifactId>groupbasedpolicy</artifactId>
+ <version>${project.version}</version>
+ <type>test-jar</type>
+ <scope>test</scope>
+ </dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
/*
- * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
+ * Copyright (c) 2016 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,
import java.util.List;
import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.binding.api.MountPointService;
import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
import org.opendaylight.controller.sal.binding.api.BindingAwareBroker;
import org.opendaylight.controller.sal.binding.api.BindingAwareProvider;
+import org.opendaylight.groupbasedpolicy.renderer.vpp.iface.InterfaceManager;
+import org.opendaylight.groupbasedpolicy.renderer.vpp.listener.VppEndpointListener;
import org.opendaylight.groupbasedpolicy.renderer.vpp.listener.VppNodeListener;
import org.opendaylight.groupbasedpolicy.renderer.vpp.manager.VppNodeManager;
import org.opendaylight.groupbasedpolicy.renderer.vpp.sf.AllowAction;
import org.opendaylight.groupbasedpolicy.renderer.vpp.sf.EtherTypeClassifier;
+import org.opendaylight.groupbasedpolicy.renderer.vpp.util.MountedDataBrokerProvider;
import org.opendaylight.groupbasedpolicy.renderer.vpp.util.VppIidFactory;
import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.renderers.Renderer;
import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.renderers.RendererBuilder;
import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableList;
+import com.google.common.eventbus.EventBus;
import com.google.common.util.concurrent.CheckedFuture;
import com.google.common.util.concurrent.FutureCallback;
import com.google.common.util.concurrent.Futures;
.setSupportedParameterValues(new EtherTypeClassifier(null).getSupportedParameterValues())
.build());
- private DataBroker dataBroker;
+ private final DataBroker dataBroker;
+
private VppNodeManager vppNodeManager;
+ private InterfaceManager interfaceManager;
+
private VppNodeListener vppNodeListener;
+ private VppEndpointListener vppEndpointListener;
public VppRenderer(DataBroker dataBroker, BindingAwareBroker bindingAwareBroker) {
this.dataBroker = Preconditions.checkNotNull(dataBroker);
if (vppNodeListener != null) {
vppNodeListener.close();
}
+ if (vppEndpointListener != null) {
+ vppEndpointListener.close();
+ }
+ if (interfaceManager != null) {
+ interfaceManager.close();
+ }
unregisterFromRendererManager();
}
public void onSessionInitiated(BindingAwareBroker.ProviderContext providerContext) {
LOG.info("starting vpp renderer");
- // vpp-node-manager
+ MountPointService mountService = Preconditions.checkNotNull(providerContext.getSALService(MountPointService.class));
+ MountedDataBrokerProvider mountDataProvider = new MountedDataBrokerProvider(mountService);
vppNodeManager = new VppNodeManager(dataBroker, providerContext);
- vppNodeListener = new VppNodeListener(dataBroker, vppNodeManager);
+
+ EventBus dtoEventBus = new EventBus("DTO events");
+ interfaceManager = new InterfaceManager(mountDataProvider, dataBroker);
+ dtoEventBus.register(interfaceManager);
+
+ vppNodeListener = new VppNodeListener(dataBroker, vppNodeManager, dtoEventBus);
+ vppEndpointListener = new VppEndpointListener(dataBroker, dtoEventBus);
registerToRendererManager();
}
\r
package org.opendaylight.groupbasedpolicy.renderer.vpp.commands;\r
\r
-import com.google.common.base.Preconditions;\r
import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction;\r
import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;\r
import org.opendaylight.groupbasedpolicy.renderer.vpp.util.General;\r
+import org.opendaylight.groupbasedpolicy.renderer.vpp.util.General.Operations;\r
import org.opendaylight.groupbasedpolicy.renderer.vpp.util.VppIidFactory;\r
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface;\r
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.InterfaceBuilder;\r
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VppInterfaceAugmentationBuilder;\r
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces._interface.L2Builder;\r
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces._interface.VhostUserBuilder;\r
-import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces._interface.l2.interconnection.BridgeBasedBuilder;\r
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.l2.attributes.interconnection.BridgeBasedBuilder;\r
import org.slf4j.Logger;\r
import org.slf4j.LoggerFactory;\r
\r
-public class VhostUserCommand extends AbstractInterfaceCommand {\r
+import com.google.common.base.Preconditions;\r
+import com.google.common.base.Strings;\r
+\r
+public class VhostUserCommand extends AbstractInterfaceCommand<VhostUserCommand> {\r
\r
private static final Logger LOG = LoggerFactory.getLogger(VhostUserCommand.class);\r
private String socket;\r
switch (getOperation()) {\r
\r
case PUT:\r
- LOG.info("Executing Add operation for command: {}", this);\r
+ LOG.debug("Executing Add operation for command: {}", this);\r
put(readWriteTransaction);\r
break;\r
case DELETE:\r
- LOG.info("Executing Delete operation for command: {}", this);\r
+ LOG.debug("Executing Delete operation for command: {}", this);\r
delete(readWriteTransaction);\r
break;\r
case MERGE:\r
- LOG.info("Executing Update operation for command: {}", this);\r
+ LOG.debug("Executing Update operation for command: {}", this);\r
merge(readWriteTransaction);\r
break;\r
default:\r
}\r
\r
private void put(ReadWriteTransaction readWriteTransaction) {\r
- Preconditions.checkNotNull(name, "Interface name should not be null");\r
-\r
InterfaceBuilder interfaceBuilder = getVhostUserInterfaceBuilder();\r
\r
readWriteTransaction.put(LogicalDatastoreType.CONFIGURATION,\r
}\r
\r
private void merge(ReadWriteTransaction readWriteTransaction) {\r
- Preconditions.checkNotNull(name, "Interface name should not be null");\r
-\r
InterfaceBuilder interfaceBuilder = getVhostUserInterfaceBuilder();\r
\r
readWriteTransaction.merge(LogicalDatastoreType.CONFIGURATION,\r
.setLinkUpDownTrapEnable(Interface.LinkUpDownTrapEnable.Enabled);\r
\r
// Create the vhost augmentation\r
- VppInterfaceAugmentation vppAugmentation =\r
- new VppInterfaceAugmentationBuilder()\r
- .setVhostUser(new VhostUserBuilder().setRole(role).setSocket(socket).build())\r
- .setL2(new L2Builder()\r
- .setInterconnection(new BridgeBasedBuilder().setBridgeDomain(bridgeDomain).build()).build())\r
- .build();\r
-\r
- interfaceBuilder.addAugmentation(VppInterfaceAugmentation.class, vppAugmentation);\r
+ VppInterfaceAugmentationBuilder vppAugmentationBuilder = new VppInterfaceAugmentationBuilder()\r
+ .setVhostUser(new VhostUserBuilder().setRole(role).setSocket(socket).build());\r
+ if (!Strings.isNullOrEmpty(bridgeDomain)) {\r
+ vppAugmentationBuilder.setL2(new L2Builder()\r
+ .setInterconnection(new BridgeBasedBuilder().setBridgeDomain(bridgeDomain).build()).build());\r
+ }\r
+\r
+ interfaceBuilder.addAugmentation(VppInterfaceAugmentation.class, vppAugmentationBuilder.build());\r
return interfaceBuilder;\r
}\r
\r
\r
}\r
\r
+ @Override\r
+ public String toString() {\r
+ return "VhostUserCommand [socket=" + socket + ", role=" + role + ", bridgeDomain=" + bridgeDomain\r
+ + ", operation=" + operation + ", name=" + name + ", description=" + description + ", enabled="\r
+ + enabled + "]";\r
+ }\r
+\r
+\r
+\r
public static class VhostUserCommandBuilder {\r
\r
private String name;\r
public VhostUserCommand build() {\r
Preconditions.checkArgument(this.name != null);\r
Preconditions.checkArgument(this.operation != null);\r
- Preconditions.checkArgument(this.socket != null);\r
+ if (operation == Operations.PUT) {\r
+ Preconditions.checkArgument(this.socket != null);\r
+ }\r
\r
return new VhostUserCommand(this);\r
}\r
--- /dev/null
+/*
+ * Copyright (c) 2016 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.groupbasedpolicy.renderer.vpp.event;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+import com.google.common.base.Optional;
+import com.google.common.base.Preconditions;
+
+public abstract class DtoChangeEvent<T extends DataObject> {
+
+ protected final InstanceIdentifier<T> iid;
+ protected final Optional<T> before;
+ protected final Optional<T> after;
+
+ public static enum DtoModificationType {
+ CREATED, UPDATED, DELETED;
+ }
+
+ public DtoChangeEvent(@Nonnull InstanceIdentifier<T> iid, @Nullable T before, @Nullable T after) {
+ this.iid = Preconditions.checkNotNull(iid);
+ Preconditions.checkArgument(!(before == null && after == null),
+ "before and after cannot be null at the same time");
+ this.before = Optional.fromNullable(before);
+ this.after = Optional.fromNullable(after);
+ }
+
+ public @Nonnull InstanceIdentifier<T> getIid() {
+ return iid;
+ }
+
+ public Optional<T> getBefore() {
+ return before;
+ }
+
+ public Optional<T> getAfter() {
+ return after;
+ }
+
+ /**
+ * Returns:<br>
+ * {@link DtoModificationType#CREATED} - when {@link #isDtoCreated()} is {@code true}<br>
+ * {@link DtoModificationType#UPDATED} - when {@link #isDtoUpdated()} is {@code true}<br>
+ * {@link DtoModificationType#DELETED} - when {@link #isDtoDeleted()} is {@code true}
+ *
+ * @return DtoModificationType
+ */
+ public @Nonnull DtoModificationType getDtoModificationType() {
+ if (isDtoCreated()) {
+ return DtoModificationType.CREATED;
+ }
+ if (isDtoUpdated()) {
+ return DtoModificationType.UPDATED;
+ }
+ if (isDtoDeleted()) {
+ return DtoModificationType.DELETED;
+ }
+ throw new IllegalStateException("Unknown DTO modification type.");
+ }
+
+ /**
+ * Checks if {@link #getBefore()} is NOT present and if {@link #getAfter()} is present
+ *
+ * @return {@code true} if DTO is created; {@code false} otherwise
+ */
+ public boolean isDtoCreated() {
+ return !before.isPresent() && after.isPresent();
+ }
+
+ /**
+ * Checks if {@link #getBefore()} is present and if {@link #getAfter()} is present
+ *
+ * @return {@code true} if DTO is updated; {@code false} otherwise
+ */
+ public boolean isDtoUpdated() {
+ return before.isPresent() && after.isPresent();
+ }
+
+ /**
+ * Checks if {@link #getBefore()} is present and if {@link #getAfter()} is NOT present
+ *
+ * @return {@code true} if DTO is deleted; {@code false} otherwise
+ */
+ public boolean isDtoDeleted() {
+ return before.isPresent() && !after.isPresent();
+ }
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + ((after == null) ? 0 : after.hashCode());
+ result = prime * result + ((before == null) ? 0 : before.hashCode());
+ result = prime * result + ((iid == null) ? 0 : iid.hashCode());
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (obj == null)
+ return false;
+ if (!(obj instanceof DtoChangeEvent))
+ return false;
+ DtoChangeEvent other = (DtoChangeEvent) obj;
+ if (after == null) {
+ if (other.after != null)
+ return false;
+ } else if (!after.equals(other.after))
+ return false;
+ if (before == null) {
+ if (other.before != null)
+ return false;
+ } else if (!before.equals(other.before))
+ return false;
+ if (iid == null) {
+ if (other.iid != null)
+ return false;
+ } else if (!iid.equals(other.iid))
+ return false;
+ return true;
+ }
+
+}
--- /dev/null
+/*
+ * Copyright (c) 2016 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.groupbasedpolicy.renderer.vpp.event;
+
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.NetconfNode;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.NetconfNodeConnectionStatus.ConnectionStatus;
+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 com.google.common.base.Optional;
+import com.google.common.base.Preconditions;
+
+public class NodeOperEvent extends DtoChangeEvent<Node> {
+
+ public NodeOperEvent(InstanceIdentifier<Node> iid, Node before, Node after) {
+ super(iid, before, after);
+ if (before != null) {
+ Preconditions.checkArgument(before.getAugmentation(NetconfNode.class) != null);
+ }
+ if (after != null) {
+ Preconditions.checkArgument(after.getAugmentation(NetconfNode.class) != null);
+ }
+ }
+
+ public boolean isAfterConnected() {
+ return isConnected(after);
+ }
+
+ public boolean isBeforeConnected() {
+ return isConnected(before);
+ }
+
+ private static boolean isConnected(Optional<Node> potentialNode) {
+ if (!potentialNode.isPresent()) {
+ return false;
+ }
+ NetconfNode netconfNode = potentialNode.get().getAugmentation(NetconfNode.class);
+ if (ConnectionStatus.Connected == netconfNode.getConnectionStatus()) {
+ return true;
+ }
+ return false;
+ }
+
+}
--- /dev/null
+/*
+ * Copyright (c) 2016 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.groupbasedpolicy.renderer.vpp.event;
+
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.vpp_renderer.rev160425.config.VppEndpoint;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+public class VppEndpointConfEvent extends DtoChangeEvent<VppEndpoint> {
+
+ public VppEndpointConfEvent(InstanceIdentifier<VppEndpoint> iid, VppEndpoint before, VppEndpoint after) {
+ super(iid, before, after);
+ }
+
+}
--- /dev/null
+/*
+ * Copyright (c) 2016 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.groupbasedpolicy.renderer.vpp.iface;
+
+import javax.annotation.Nonnull;
+
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction;
+import org.opendaylight.groupbasedpolicy.renderer.vpp.commands.ConfigCommand;
+import org.opendaylight.groupbasedpolicy.renderer.vpp.commands.VhostUserCommand;
+import org.opendaylight.groupbasedpolicy.renderer.vpp.commands.VhostUserCommand.VhostUserCommandBuilder;
+import org.opendaylight.groupbasedpolicy.renderer.vpp.event.NodeOperEvent;
+import org.opendaylight.groupbasedpolicy.renderer.vpp.event.VppEndpointConfEvent;
+import org.opendaylight.groupbasedpolicy.renderer.vpp.util.General.Operations;
+import org.opendaylight.groupbasedpolicy.renderer.vpp.util.MountedDataBrokerProvider;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.vpp_renderer.rev160425.config.VppEndpoint;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.vpp_renderer.rev160425.config.vpp.endpoint.InterfaceTypeChoice;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.vpp_renderer.rev160425.config.vpp.endpoint._interface.type.choice.VhostUserCase;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VhostUserRole;
+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.base.Preconditions;
+import com.google.common.base.Strings;
+import com.google.common.eventbus.Subscribe;
+import com.google.common.util.concurrent.FutureCallback;
+import com.google.common.util.concurrent.Futures;
+
+public class InterfaceManager implements AutoCloseable {
+
+ private static final Logger LOG = LoggerFactory.getLogger(InterfaceManager.class);
+ private final MountedDataBrokerProvider mountDataProvider;
+ private final VppEndpointLocationProvider vppEndpointLocationProvider;
+
+ public InterfaceManager(@Nonnull MountedDataBrokerProvider mountDataProvider, @Nonnull DataBroker dataProvider) {
+ this.mountDataProvider = Preconditions.checkNotNull(mountDataProvider);
+ this.vppEndpointLocationProvider = new VppEndpointLocationProvider(dataProvider);
+ }
+
+ @Subscribe
+ public void vppEndpointChanged(VppEndpointConfEvent event) {
+ switch (event.getDtoModificationType()) {
+ case CREATED:
+ vppEndpointCreated(event.getAfter().get());
+ break;
+ case UPDATED:
+ vppEndpointDeleted(event.getBefore().get());
+ vppEndpointCreated(event.getAfter().get());
+ break;
+ case DELETED:
+ vppEndpointDeleted(event.getBefore().get());
+ break;
+ }
+ }
+
+ private void vppEndpointCreated(VppEndpoint vppEndpoint) {
+ Optional<ConfigCommand> potentialIfaceCommand = createInterfaceWithoutBdCommand(vppEndpoint, Operations.PUT);
+ if (!potentialIfaceCommand.isPresent()) {
+ return;
+ }
+ ConfigCommand ifaceWithoutBdCommand = potentialIfaceCommand.get();
+ InstanceIdentifier<?> vppNodeIid = vppEndpoint.getVppNodePath();
+ Optional<DataBroker> potentialVppDataProvider = mountDataProvider.getDataBrokerForMountPoint(vppNodeIid);
+ if (!potentialVppDataProvider.isPresent()) {
+ LOG.debug("Cannot get data broker for mount point {}", vppNodeIid);
+ return;
+ }
+ DataBroker vppDataBroker = potentialVppDataProvider.get();
+ createIfaceOnVpp(ifaceWithoutBdCommand, vppDataBroker, vppEndpoint, vppNodeIid);
+ }
+
+ private void createIfaceOnVpp(ConfigCommand createIfaceWithoutBdCommand, DataBroker vppDataBroker,
+ VppEndpoint vppEndpoint, InstanceIdentifier<?> vppNodeIid) {
+ ReadWriteTransaction rwTx = vppDataBroker.newReadWriteTransaction();
+ createIfaceWithoutBdCommand.execute(rwTx);
+ Futures.addCallback(rwTx.submit(), new FutureCallback<Void>() {
+
+ @Override
+ public void onSuccess(Void result) {
+ LOG.debug("Create interface on VPP command was successful:\nVPP: {}\nCommand: {}", vppNodeIid,
+ createIfaceWithoutBdCommand);
+ vppEndpointLocationProvider.createLocationForVppEndpoint(vppEndpoint);
+ }
+
+ @Override
+ public void onFailure(Throwable t) {
+ LOG.error("Create interface on VPP command was NOT successful:\nVPP: {}\nCommand: {}", vppNodeIid,
+ createIfaceWithoutBdCommand, t);
+ }
+ });
+ }
+
+ private void vppEndpointDeleted(VppEndpoint vppEndpoint) {
+ Optional<ConfigCommand> potentialIfaceCommand = createInterfaceWithoutBdCommand(vppEndpoint, Operations.DELETE);
+ if (!potentialIfaceCommand.isPresent()) {
+ return;
+ }
+ ConfigCommand ifaceWithoutBdCommand = potentialIfaceCommand.get();
+ InstanceIdentifier<?> vppNodeIid = vppEndpoint.getVppNodePath();
+ Optional<DataBroker> potentialVppDataProvider = mountDataProvider.getDataBrokerForMountPoint(vppNodeIid);
+ if (!potentialVppDataProvider.isPresent()) {
+ LOG.debug("Cannot get data broker for mount point {}", vppNodeIid);
+ return;
+ }
+ DataBroker vppDataBroker = potentialVppDataProvider.get();
+ deleteIfaceOnVpp(ifaceWithoutBdCommand, vppDataBroker, vppEndpoint, vppNodeIid);
+ }
+
+ private void deleteIfaceOnVpp(ConfigCommand deleteIfaceWithoutBdCommand, DataBroker vppDataBroker,
+ VppEndpoint vppEndpoint, InstanceIdentifier<?> vppNodeIid) {
+ ReadWriteTransaction rwTx = vppDataBroker.newReadWriteTransaction();
+ deleteIfaceWithoutBdCommand.execute(rwTx);
+ Futures.addCallback(rwTx.submit(), new FutureCallback<Void>() {
+
+ @Override
+ public void onSuccess(Void result) {
+ LOG.debug("Delete interface on VPP command was successful:\nVPP: {}\nCommand: {}", vppNodeIid,
+ deleteIfaceWithoutBdCommand);
+ vppEndpointLocationProvider.deleteLocationForVppEndpoint(vppEndpoint);
+ }
+
+ @Override
+ public void onFailure(Throwable t) {
+ LOG.error("Delete interface on VPP command was NOT successful:\nVPP: {}\nCommand: {}", vppNodeIid,
+ deleteIfaceWithoutBdCommand, t);
+ }
+ });
+ }
+
+ @Subscribe
+ public void vppNodeChanged(NodeOperEvent event) {
+ switch (event.getDtoModificationType()) {
+ case CREATED:
+ if (event.isAfterConnected()) {
+ // TODO read VppEndpoints or cache them during vppEndpointChanged()
+ }
+ break;
+ case UPDATED:
+ if (!event.isBeforeConnected() && event.isAfterConnected()) {
+ // TODO reconciliation - diff between disconnected snapshot and current snapshot
+ }
+ break;
+ case DELETED:
+ if (event.isBeforeConnected()) {
+ // TODO we could do snapshot of VppEndpoints
+ // which can be used for reconciliation
+ }
+ break;
+ }
+ }
+
+ private static Optional<ConfigCommand> createInterfaceWithoutBdCommand(@Nonnull VppEndpoint vppEp,
+ @Nonnull Operations operations) {
+ if (!hasNodeAndInterface(vppEp)) {
+ LOG.debug("Interface command is not created for {}", vppEp);
+ return Optional.absent();
+ }
+ VhostUserCommandBuilder builder = VhostUserCommand.builder();
+ builder.setName(vppEp.getVppInterfaceName());
+ InterfaceTypeChoice interfaceTypeChoice = vppEp.getInterfaceTypeChoice();
+ if (interfaceTypeChoice instanceof VhostUserCase) {
+ VhostUserCase vhostUserIface = (VhostUserCase) interfaceTypeChoice;
+ String socket = vhostUserIface.getSocket();
+ if (Strings.isNullOrEmpty(socket)) {
+ LOG.debug("Vhost user interface command is not created because socket is missing. {}", vppEp);
+ return Optional.absent();
+ }
+ builder.setSocket(socket);
+ builder.setRole(VhostUserRole.Client);
+ }
+ VhostUserCommand vhostUserCommand =
+ builder.setOperation(operations).setDescription(vppEp.getDescription()).build();
+ return Optional.of(vhostUserCommand);
+ }
+
+ private static boolean hasNodeAndInterface(VppEndpoint vppEp) {
+ if (vppEp.getVppNodePath() == null) {
+ LOG.trace("vpp-node is missing. {}", vppEp);
+ return false;
+ }
+ if (Strings.isNullOrEmpty(vppEp.getVppInterfaceName())) {
+ LOG.trace("vpp-interface-name is missing. {}", vppEp);
+ return false;
+ }
+ return true;
+ }
+
+ @Override
+ public void close() throws Exception {
+ vppEndpointLocationProvider.close();
+ }
+
+}
--- /dev/null
+/*
+ * Copyright (c) 2016 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.groupbasedpolicy.renderer.vpp.iface;
+
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.groupbasedpolicy.util.IidFactory;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.has.absolute.location.AbsoluteLocation;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.has.absolute.location.AbsoluteLocationBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.has.absolute.location.absolute.location.location.type.ExternalLocationCaseBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint_location_provider.rev160419.ProviderName;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint_location_provider.rev160419.location.providers.LocationProvider;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint_location_provider.rev160419.location.providers.LocationProviderBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint_location_provider.rev160419.location.providers.location.provider.ProviderAddressEndpointLocation;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint_location_provider.rev160419.location.providers.location.provider.ProviderAddressEndpointLocationBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint_location_provider.rev160419.location.providers.location.provider.ProviderAddressEndpointLocationKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.vpp_renderer.rev160425.config.VppEndpoint;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.base.Preconditions;
+import com.google.common.util.concurrent.FutureCallback;
+import com.google.common.util.concurrent.Futures;
+
+public class VppEndpointLocationProvider implements AutoCloseable {
+
+ private static final Logger LOG = LoggerFactory.getLogger(VppEndpointLocationProvider.class);
+ public static final ProviderName VPP_ENDPOINT_LOCATION_PROVIDER =
+ new ProviderName("VPP endpoint location provider");
+ public static final long PROVIDER_PRIORITY = 10L;
+ private static final String INTERFACE_PATH = "/ietf-interfaces:interfaces/ietf-interfaces:interface";
+ private final DataBroker dataProvider;
+
+ public VppEndpointLocationProvider(DataBroker dataProvider) {
+ this.dataProvider = Preconditions.checkNotNull(dataProvider);
+ LocationProvider locationProvider = new LocationProviderBuilder().setProvider(VPP_ENDPOINT_LOCATION_PROVIDER)
+ .setPriority(PROVIDER_PRIORITY)
+ .build();
+ WriteTransaction wTx = dataProvider.newWriteOnlyTransaction();
+ wTx.put(LogicalDatastoreType.CONFIGURATION, IidFactory.locationProviderIid(VPP_ENDPOINT_LOCATION_PROVIDER),
+ locationProvider, true);
+
+ Futures.addCallback(wTx.submit(), new FutureCallback<Void>() {
+
+ @Override
+ public void onSuccess(Void result) {
+ LOG.trace("{} was created", VPP_ENDPOINT_LOCATION_PROVIDER.getValue());
+ }
+
+ @Override
+ public void onFailure(Throwable t) {
+ LOG.error("{} was NOT created", VPP_ENDPOINT_LOCATION_PROVIDER.getValue());
+ }
+ });
+ }
+
+ public void createLocationForVppEndpoint(VppEndpoint vppEndpoint) {
+ ProviderAddressEndpointLocation providerAddressEndpointLocation =
+ createProviderAddressEndpointLocation(vppEndpoint);
+ WriteTransaction wTx = dataProvider.newWriteOnlyTransaction();
+ wTx.put(LogicalDatastoreType.CONFIGURATION,
+ IidFactory.providerAddressEndpointLocationIid(VPP_ENDPOINT_LOCATION_PROVIDER,
+ providerAddressEndpointLocation.getKey()),
+ providerAddressEndpointLocation);
+
+ Futures.addCallback(wTx.submit(), new FutureCallback<Void>() {
+
+ @Override
+ public void onSuccess(Void result) {
+ LOG.trace("{} provides location: {}", VPP_ENDPOINT_LOCATION_PROVIDER.getValue(),
+ providerAddressEndpointLocation);
+ }
+
+ @Override
+ public void onFailure(Throwable t) {
+ LOG.error("{} failed to provide location: {}", VPP_ENDPOINT_LOCATION_PROVIDER.getValue(),
+ providerAddressEndpointLocation, t);
+ }
+ });
+ }
+
+ public static ProviderAddressEndpointLocation createProviderAddressEndpointLocation(VppEndpoint vppEndpoint) {
+ String restIfacePath = INTERFACE_PATH + createRestInterfaceKey(vppEndpoint.getVppInterfaceName());
+ AbsoluteLocation absoluteLocation = new AbsoluteLocationBuilder()
+ .setLocationType(new ExternalLocationCaseBuilder().setExternalNodeMountPoint(vppEndpoint.getVppNodePath())
+ .setExternalNodeConnector(restIfacePath)
+ .build())
+ .build();
+ return new ProviderAddressEndpointLocationBuilder()
+ .setKey(createProviderAddressEndpointLocationKey(vppEndpoint))
+ .setAbsoluteLocation(absoluteLocation)
+ .build();
+ }
+
+ public void deleteLocationForVppEndpoint(VppEndpoint vppEndpoint) {
+ ProviderAddressEndpointLocationKey provAddrEpLocKey = createProviderAddressEndpointLocationKey(vppEndpoint);
+ WriteTransaction wTx = dataProvider.newWriteOnlyTransaction();
+ wTx.delete(LogicalDatastoreType.CONFIGURATION,
+ IidFactory.providerAddressEndpointLocationIid(VPP_ENDPOINT_LOCATION_PROVIDER, provAddrEpLocKey));
+ Futures.addCallback(wTx.submit(), new FutureCallback<Void>() {
+
+ @Override
+ public void onSuccess(Void result) {
+ LOG.trace("{} removes location: {}", VPP_ENDPOINT_LOCATION_PROVIDER.getValue(), provAddrEpLocKey);
+ }
+
+ @Override
+ public void onFailure(Throwable t) {
+ LOG.error("{} failed to remove location: {}", VPP_ENDPOINT_LOCATION_PROVIDER.getValue(),
+ provAddrEpLocKey, t);
+ }
+ });
+ }
+
+ private static ProviderAddressEndpointLocationKey createProviderAddressEndpointLocationKey(VppEndpoint vppEndpoint) {
+ return new ProviderAddressEndpointLocationKey(vppEndpoint.getAddress(), vppEndpoint.getAddressType(),
+ vppEndpoint.getContextId(), vppEndpoint.getContextType());
+ }
+
+ private static String createRestInterfaceKey(String ifaceName) {
+ return "[ietf-interfaces:name='" + ifaceName + "']";
+ }
+
+ @Override
+ public void close() throws Exception {
+ WriteTransaction wTx = dataProvider.newWriteOnlyTransaction();
+ wTx.delete(LogicalDatastoreType.CONFIGURATION, IidFactory.locationProviderIid(VPP_ENDPOINT_LOCATION_PROVIDER));
+ wTx.submit();
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2016 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.groupbasedpolicy.renderer.vpp.listener;
+
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.binding.api.DataObjectModification;
+import org.opendaylight.controller.md.sal.binding.api.DataTreeIdentifier;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.groupbasedpolicy.util.DataTreeChangeHandler;
+import org.opendaylight.groupbasedpolicy.util.IidFactory;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.RendererName;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.renderers.renderer.RendererPolicy;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+public class RendererPolicyListener extends DataTreeChangeHandler<RendererPolicy> {
+
+ // TODO move to common place
+ private static final RendererName RENDERER_NAME = new RendererName("VPP renderer");
+
+ protected RendererPolicyListener(DataBroker dataProvider) {
+ super(dataProvider);
+ registerDataTreeChangeListener(new DataTreeIdentifier<>(LogicalDatastoreType.CONFIGURATION,
+ IidFactory.rendererIid(RENDERER_NAME).child(RendererPolicy.class)));
+ }
+
+ @Override
+ protected void onWrite(DataObjectModification<RendererPolicy> rootNode,
+ InstanceIdentifier<RendererPolicy> rootIdentifier) {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ protected void onDelete(DataObjectModification<RendererPolicy> rootNode,
+ InstanceIdentifier<RendererPolicy> rootIdentifier) {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ protected void onSubtreeModified(DataObjectModification<RendererPolicy> rootNode,
+ InstanceIdentifier<RendererPolicy> rootIdentifier) {
+ // TODO Auto-generated method stub
+
+ }
+
+}
--- /dev/null
+/*
+ * Copyright (c) 2016 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.groupbasedpolicy.renderer.vpp.listener;
+
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.binding.api.DataObjectModification;
+import org.opendaylight.controller.md.sal.binding.api.DataTreeIdentifier;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.groupbasedpolicy.renderer.vpp.event.VppEndpointConfEvent;
+import org.opendaylight.groupbasedpolicy.util.DataTreeChangeHandler;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.vpp_renderer.rev160425.Config;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.vpp_renderer.rev160425.config.VppEndpoint;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.base.Preconditions;
+import com.google.common.eventbus.EventBus;
+
+public class VppEndpointListener extends DataTreeChangeHandler<VppEndpoint> {
+
+ private static final Logger LOG = LoggerFactory.getLogger(VppEndpointListener.class);
+ private EventBus eventBus;
+
+ public VppEndpointListener(DataBroker dataProvider, EventBus eventBus) {
+ super(dataProvider);
+ this.eventBus = Preconditions.checkNotNull(eventBus);
+ registerDataTreeChangeListener(new DataTreeIdentifier<>(LogicalDatastoreType.CONFIGURATION,
+ InstanceIdentifier.builder(Config.class).child(VppEndpoint.class).build()));
+ }
+
+ @Override
+ protected void onWrite(DataObjectModification<VppEndpoint> rootNode,
+ InstanceIdentifier<VppEndpoint> rootIdentifier) {
+ VppEndpointConfEvent event =
+ new VppEndpointConfEvent(rootIdentifier, rootNode.getDataBefore(), rootNode.getDataAfter());
+ LOG.trace("Dispatching event on write: {}", event);
+ eventBus.post(event);
+ }
+
+ @Override
+ protected void onDelete(DataObjectModification<VppEndpoint> rootNode,
+ InstanceIdentifier<VppEndpoint> rootIdentifier) {
+ VppEndpointConfEvent event =
+ new VppEndpointConfEvent(rootIdentifier, rootNode.getDataBefore(), rootNode.getDataAfter());
+ LOG.trace("Dispatching event on delete: {}", event);
+ eventBus.post(event);
+ }
+
+ @Override
+ protected void onSubtreeModified(DataObjectModification<VppEndpoint> rootNode,
+ InstanceIdentifier<VppEndpoint> rootIdentifier) {
+ VppEndpointConfEvent event =
+ new VppEndpointConfEvent(rootIdentifier, rootNode.getDataBefore(), rootNode.getDataAfter());
+ LOG.trace("Dispatching event on subtree modified: {}", event);
+ eventBus.post(event);
+ }
+
+}
import org.opendaylight.controller.md.sal.binding.api.DataTreeIdentifier;
import org.opendaylight.controller.md.sal.binding.api.DataTreeModification;
import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.groupbasedpolicy.renderer.vpp.event.NodeOperEvent;
import org.opendaylight.groupbasedpolicy.renderer.vpp.manager.VppNodeManager;
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.network.topology.Topology;
import org.slf4j.LoggerFactory;
import com.google.common.base.Preconditions;
+import com.google.common.eventbus.EventBus;
public class VppNodeListener implements DataTreeChangeListener<Node>, AutoCloseable {
private final ListenerRegistration<VppNodeListener> listenerRegistration;
private final VppNodeManager nodeManager;
+ private final EventBus eventBus;
- public VppNodeListener(DataBroker dataBroker, VppNodeManager nodeManager) {
+ public VppNodeListener(DataBroker dataBroker, VppNodeManager nodeManager, EventBus eventBus) {
this.nodeManager = Preconditions.checkNotNull(nodeManager);
+ this.eventBus = Preconditions.checkNotNull(eventBus);
// Register listener
final DataTreeIdentifier<Node> networkTopologyPath = new DataTreeIdentifier<>(LogicalDatastoreType.OPERATIONAL,
InstanceIdentifier.builder(NetworkTopology.class).child(Topology.class).child(Node.class).build());
DataObjectModification<Node> rootNode = modification.getRootNode();
Node dataAfter = rootNode.getDataAfter();
Node dataBefore = rootNode.getDataBefore();
+ NodeOperEvent event =
+ new NodeOperEvent(modification.getRootPath().getRootIdentifier(), dataBefore, dataAfter);
+ eventBus.post(event);
nodeManager.syncNodes(dataAfter, dataBefore);
}
}
--- /dev/null
+/*
+ * Copyright (c) 2016 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.groupbasedpolicy.renderer.vpp.util;
+
+import javax.annotation.Nonnull;
+
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.binding.api.MountPoint;
+import org.opendaylight.controller.md.sal.binding.api.MountPointService;
+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.base.Preconditions;
+
+public class MountedDataBrokerProvider {
+
+ private static final Logger LOG = LoggerFactory.getLogger(MountedDataBrokerProvider.class);
+ private final MountPointService mountService;
+
+ public MountedDataBrokerProvider(@Nonnull MountPointService mountService) {
+ this.mountService = Preconditions.checkNotNull(mountService);
+ }
+
+ public Optional<DataBroker> getDataBrokerForMountPoint(@Nonnull InstanceIdentifier<?> iidToMountPoint) {
+ Optional<MountPoint> potentialMountPoint = mountService.getMountPoint(iidToMountPoint);
+ if (!potentialMountPoint.isPresent()) {
+ LOG.debug("Mount point does not exist for {}", iidToMountPoint);
+ return Optional.absent();
+ }
+ return potentialMountPoint.get().getService(DataBroker.class);
+ }
+}
}
}
+ identity vxlan-gpe-tunnel {
+ base if:interface-type;
+ }
+
+ typedef vxlan-gpe-vni {
+ description "VNI used in a VXLAN-GPE tunnel";
+ type uint32 {
+ range "0..16777215";
+ }
+ }
+
+ typedef vxlan-gpe-next-protocol {
+ type enumeration {
+ enum ipv4;
+ enum ipv6;
+ enum ethernet;
+ enum nsh;
+ }
+ }
+
grouping bridge-domain-attributes {
leaf flood {
type boolean;
}
}
+ grouping ethernet-base-attributes {
+ leaf mtu {
+ type uint16 {
+ range "64..9216";
+ }
+ units "octets";
+ default 9216;
+ description
+ "The size, in octets, of the largest packet that the
+ hardware interface will send and receive.";
+ }
+ }
+
+ grouping ethernet-state-attributes {
+ leaf manufacturer-description {
+ type string;
+ config false;
+ }
+ leaf duplex {
+ type enumeration {
+ enum "half";
+ enum "full";
+ }
+ config false;
+ }
+ }
+
grouping vhost-user-interface-base-attributes {
leaf socket {
type string {
type vhost-user-role;
default "server";
}
+ description "vhost-user settings";
}
grouping vhost-user-interface-state-attributes {
- leaf features {
- type uint64;
- config false;
- }
- leaf virtio-net-hdr-size {
- type uint32;
- config false;
- }
- leaf num-memory-regions {
- type uint32;
- config false;
- }
- leaf connect-error {
- type string;
- config false;
- }
+ leaf features {
+ type uint64;
+ config false;
+ }
+ leaf virtio-net-hdr-size {
+ type uint32;
+ config false;
+ }
+ leaf num-memory-regions {
+ type uint32;
+ config false;
+ }
+ leaf connect-error {
+ type string;
+ config false;
+ }
+ }
+
+ grouping vxlan-base-attributes {
+ // FIXME: this should be in an vxlan-specific extension
+ leaf src {
+ /*mandatory true;*/
+ type inet:ip-address;
+ }
+ leaf dst {
+ /*mandatory true;*/
+ type inet:ip-address;
+ }
+ leaf vni {
+ /*mandatory true;*/
+ type vxlan-vni;
+ }
+ leaf encap-vrf-id {
+ type uint32;
+ }
+ }
+
+ grouping vxlan-gpe-base-attributes {
+ leaf local {
+ /*mandatory true;*/
+ type inet:ip-address;
+ }
+ leaf remote {
+ /*mandatory true;*/
+ type inet:ip-address;
+ }
+ leaf vni {
+ /*mandatory true;*/
+ type vxlan-gpe-vni;
+ }
+ leaf next-protocol {
+ type vxlan-gpe-next-protocol;
+ }
+ leaf encap-vrf-id {
+ type uint32;
+ }
+ leaf decap-vrf-id {
+ type uint32;
+ }
}
grouping vlan-tag-rewrite-attributes {
}
}
- augment /if:interfaces/if:interface {
- ext:augment-identifier "vpp-interface-augmentation";
-
- // FIXME using ietf-interfaces model for vpp interfaces makes it hard to implement because:
- // 1. The link between interface type and this augmentation is unclear
- // 2. Only this augmentation with combination of ifc type is trigger to do something for vpp, what if user only configures base interface stuff ? + We need to get leaves defined by ietf-interfaces when we are processing this augment
-
- container sub-interface {
- when "../if:type = 'v3po:sub-interface'";
- leaf super-interface {
- type if:interface-ref;
- }
- uses sub-interface-base-attributes;
- }
-
- container tap {
- when "../if:type = 'v3po:tap'";
- uses tap-interface-base-attributes;
- uses tap-interface-config-attributes;
- }
-
- container ethernet {
- when "../if:type = 'ianaift:ethernetCsmacd'";
- leaf mtu {
- type uint16 {
- range "64..9216";
- }
- units "octets";
- default 9216;
- description
- "The size, in octets, of the largest packet that the
- hardware interface will send and receive.";
- }
- }
- container routing {
- leaf vrf-id {
- type uint32;
- default 0;
- }
- }
- container vhost-user {
- when "../if:type = 'v3po:vhost-user'";
- uses vhost-user-interface-base-attributes;
- description "vhost-user settings";
- }
- container vxlan {
- // FIXME: this should be in an vxlan-specific extension
- when "../if:type = 'v3po:vxlan-tunnel'";
-
- leaf src {
- /*mandatory true;*/
- type inet:ip-address;
- }
- leaf dst {
- /*mandatory true;*/
- type inet:ip-address;
- }
- leaf vni {
- /*mandatory true;*/
- type vxlan-vni;
- }
- leaf encap-vrf-id {
- type uint32;
- }
- }
- container l2 {
+ grouping l2-attributes {
description
"Parameters for configuring Layer2 features on interfaces.";
- must "(not (../if:ipv4[if:enabled = 'true']/if:address/if:ip) and " +
- "not (../if:ipv6[if:enabled = 'true']/if:address/if:ip))";
choice interconnection {
case xconnect-based {
leaf xconnect-outgoing-interface {
/* Don't allow selection of this interface */
must "../../if:name != current()";
- type if:interface-ref;
+ type if:interface-ref; // todo use interface-state-ref for operational data?
description
"L2 xconnect mode";
}
}
}
}
- container vlan-tag-rewrite {
+ container vlan-tag-rewrite { // todo valid only for sub-interfaces
uses vlan-tag-rewrite-attributes;
}
+ }
+
+ augment /if:interfaces/if:interface {
+ ext:augment-identifier "vpp-interface-augmentation";
+
+ // FIXME using ietf-interfaces model for vpp interfaces makes it hard to implement because:
+ // 1. The link between interface type and this augmentation is unclear
+ // 2. Only this augmentation with combination of ifc type is trigger to do something for vpp, what if user only configures base interface stuff ? + We need to get leaves defined by ietf-interfaces when we are processing this augment
+ // 3. The ietf-interfaces model does not define groupings which makes types reuse difficult
+
+ container sub-interface {
+ when "../if:type = 'v3po:sub-interface'";
+ leaf super-interface {
+ type if:interface-ref;
+ }
+ uses sub-interface-base-attributes;
+ }
+
+ container tap {
+ when "../if:type = 'v3po:tap'";
+ uses tap-interface-base-attributes;
+ uses tap-interface-config-attributes;
+ }
+
+ container ethernet {
+ when "../if:type = 'ianaift:ethernetCsmacd'";
+ uses ethernet-base-attributes;
+ }
+
+ container routing {
+ leaf vrf-id { // todo no routing info for oper, is it possible to get it from the vpp?
+ type uint32;
+ default 0;
+ }
+ }
+
+ container vhost-user {
+ when "../if:type = 'v3po:vhost-user'";
+ uses vhost-user-interface-base-attributes;
+ }
+
+ container vxlan {
+ when "../if:type = 'v3po:vxlan-tunnel'";
+ uses vxlan-base-attributes;
+ }
+
+ container l2 {
+ must "(not (../if:ipv4[if:enabled = 'true']/if:address/if:ip) and " +
+ "not (../if:ipv6[if:enabled = 'true']/if:address/if:ip))";
+
+ uses l2-attributes;
+ }
+
+ container vxlan-gpe {
+ when "../if:type = 'v3po:vxlan-gpe-tunnel'";
+
+ uses vxlan-gpe-base-attributes;
}
}
container tap {
when "../if:type = 'v3po:tap'";
- uses tap-interface-base-attributes {
- refine tap-name {
- config false;
- }
- }
+ uses tap-interface-base-attributes;
}
container ethernet {
when "../if:type = 'ianaift:ethernetCsmacd'";
- leaf mtu {
- type uint16;
- }
- leaf manufacturer-description {
- type string;
- }
- leaf duplex {
- type enumeration {
- enum "half";
- enum "full";
- }
- }
+ uses ethernet-base-attributes;
+ uses ethernet-state-attributes;
}
+
container vhost-user {
when "../if:type = 'v3po:vhost-user'";
- uses vhost-user-interface-base-attributes {
- refine socket {
- config false;
- }
- refine role {
- config false;
- }
- }
+ uses vhost-user-interface-base-attributes;
uses vhost-user-interface-state-attributes;
}
+
container vxlan {
when "../if:type = 'v3po:vxlan-tunnel'";
+ uses vxlan-base-attributes;
+ }
+ container vxlan-gpe {
+ when "../if:type = 'v3po:vxlan-gpe-tunnel'";
- leaf src {
- type inet:ip-address;
- }
- leaf dst {
- type inet:ip-address;
- }
-
- leaf vni {
- type uint32;
- }
- leaf encap-vrf-id {
- type uint32;
- }
+ uses vxlan-gpe-base-attributes;
}
+
container l2 {
- choice interconnection {
- case xconnect-based {
- leaf xconnect-outgoing-interface {
- type if:interface-ref;
- }
- }
- case bridge-based {
- leaf bridge-domain {
- type bridge-domain-ref;
- }
- leaf split-horizon-group {
- type uint8;
- }
- leaf bridged-virtual-interface {
- type boolean;
- }
- }
- }
- container vlan-tag-rewrite {
- uses vlan-tag-rewrite-attributes;
- }
+ must "(not (../if:ipv4[if:enabled = 'true']/if:address/if:ip) and " +
+ "not (../if:ipv6[if:enabled = 'true']/if:address/if:ip))";
+
+ uses l2-attributes;
}
}
\r
package org.opendaylight.groupbasedpolicy.renderer.vpp.commands;\r
\r
-import com.google.common.base.Optional;\r
import org.junit.Assert;\r
import org.junit.Before;\r
import org.junit.Test;\r
import org.opendaylight.groupbasedpolicy.renderer.vpp.util.General;\r
import org.opendaylight.groupbasedpolicy.renderer.vpp.util.VppIidFactory;\r
import org.opendaylight.groupbasedpolicy.util.DataStoreHelper;\r
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface;\r
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.InterfaceBuilder;\r
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.InterfaceKey;\r
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VhostUserRole;\r
-import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface;\r
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VppInterfaceAugmentation;\r
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VppInterfaceAugmentationBuilder;\r
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces._interface.L2Builder;\r
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces._interface.VhostUser;\r
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces._interface.VhostUserBuilder;\r
-import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces._interface.l2.interconnection.BridgeBased;\r
-import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces._interface.l2.interconnection.BridgeBasedBuilder;\r
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.l2.attributes.interconnection.BridgeBased;\r
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.l2.attributes.interconnection.BridgeBasedBuilder;\r
+\r
+import com.google.common.base.Optional;\r
\r
public class VhostUserCommandTest extends VppRendererDataBrokerTest {\r
\r
--- /dev/null
+/*
+ * Copyright (c) 2016 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.groupbasedpolicy.renderer.vpp.event;
+
+import org.junit.Assert;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+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.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.Node;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.NodeBuilder;
+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;
+
+public class DtoChangeEventTest {
+
+ private final static TopologyKey TOPO_KEY = new TopologyKey(new TopologyId("topo1"));
+ private final static NodeKey NODE_KEY = new NodeKey(new NodeId("node1"));
+ private final static InstanceIdentifier<Node> NODE_IID = InstanceIdentifier.builder(NetworkTopology.class)
+ .child(Topology.class, TOPO_KEY)
+ .child(Node.class, NODE_KEY)
+ .build();
+
+ @Rule
+ public ExpectedException thrown = ExpectedException.none();
+
+ private static class DummyDtoEvent extends DtoChangeEvent<Node> {
+
+ public DummyDtoEvent(InstanceIdentifier<Node> iid, Node before, Node after) {
+ super(iid, before, after);
+ }
+ }
+
+ @Test
+ public void testConstructor_nodeCreated() {
+ Node node = new NodeBuilder().setKey(NODE_KEY).build();
+ DummyDtoEvent event = new DummyDtoEvent(NODE_IID, null, node);
+ Assert.assertNotNull(event.getIid());
+ Assert.assertTrue(event.getAfter().isPresent());
+ Assert.assertFalse(event.getBefore().isPresent());
+ Assert.assertEquals(DtoChangeEvent.DtoModificationType.CREATED, event.getDtoModificationType());
+ Assert.assertTrue(event.isDtoCreated());
+ Assert.assertFalse(event.isDtoDeleted());
+ Assert.assertFalse(event.isDtoUpdated());
+ }
+
+ @Test
+ public void testConstructor_nodeDeleted() {
+ Node node = new NodeBuilder().setKey(NODE_KEY).build();
+ DummyDtoEvent event = new DummyDtoEvent(NODE_IID, node, null);
+ Assert.assertNotNull(event.getIid());
+ Assert.assertFalse(event.getAfter().isPresent());
+ Assert.assertTrue(event.getBefore().isPresent());
+ Assert.assertEquals(DtoChangeEvent.DtoModificationType.DELETED, event.getDtoModificationType());
+ Assert.assertFalse(event.isDtoCreated());
+ Assert.assertTrue(event.isDtoDeleted());
+ Assert.assertFalse(event.isDtoUpdated());
+ }
+
+ @Test
+ public void testConstructor_nodeUpdated() {
+ Node node = new NodeBuilder().setKey(NODE_KEY).build();
+ DummyDtoEvent event = new DummyDtoEvent(NODE_IID, node, node);
+ Assert.assertNotNull(event.getIid());
+ Assert.assertTrue(event.getAfter().isPresent());
+ Assert.assertTrue(event.getBefore().isPresent());
+ Assert.assertEquals(DtoChangeEvent.DtoModificationType.UPDATED, event.getDtoModificationType());
+ Assert.assertFalse(event.isDtoCreated());
+ Assert.assertFalse(event.isDtoDeleted());
+ Assert.assertTrue(event.isDtoUpdated());
+ }
+
+ @Test
+ public void testConstructor_nullNodes_Exception() {
+ thrown.expect(IllegalArgumentException.class);
+ new DummyDtoEvent(NODE_IID, null, null);
+ }
+
+ @Test
+ public void testConstructor_nullIid_Exception() {
+ Node node = new NodeBuilder().setKey(NODE_KEY).build();
+ thrown.expect(NullPointerException.class);
+ new DummyDtoEvent(null, node, node);
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2016 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.groupbasedpolicy.renderer.vpp.event;
+
+import org.junit.Assert;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.NetconfNode;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.NetconfNodeBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.NetconfNodeConnectionStatus.ConnectionStatus;
+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.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.Node;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.NodeBuilder;
+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;
+
+public class NodeOperEventTest {
+
+ private final static TopologyKey TOPO_KEY = new TopologyKey(new TopologyId("topo1"));
+ private final static NodeKey NODE_KEY = new NodeKey(new NodeId("node1"));
+ private final static InstanceIdentifier<Node> NODE_IID = InstanceIdentifier.builder(NetworkTopology.class)
+ .child(Topology.class, TOPO_KEY)
+ .child(Node.class, NODE_KEY)
+ .build();
+ private final static NetconfNode NETCONF_NODE_AUG_CONNECTED =
+ new NetconfNodeBuilder().setConnectionStatus(ConnectionStatus.Connected).build();
+ private final static NetconfNode NETCONF_NODE_AUG_CONNECTING =
+ new NetconfNodeBuilder().setConnectionStatus(ConnectionStatus.Connecting).build();
+
+ @Rule
+ public ExpectedException thrown = ExpectedException.none();
+
+ @Test
+ public void testConstructor_nodeCreated() {
+ Node node = new NodeBuilder().setKey(NODE_KEY)
+ .addAugmentation(NetconfNode.class, NETCONF_NODE_AUG_CONNECTED)
+ .build();
+ NodeOperEvent event = new NodeOperEvent(NODE_IID, null, node);
+ Assert.assertTrue(event.getAfter().isPresent());
+ Assert.assertFalse(event.getBefore().isPresent());
+ }
+
+ @Test
+ public void testConstructor_nodeDeleted() {
+ Node node = new NodeBuilder().setKey(NODE_KEY)
+ .addAugmentation(NetconfNode.class, NETCONF_NODE_AUG_CONNECTED)
+ .build();
+ NodeOperEvent event = new NodeOperEvent(NODE_IID, node, null);
+ Assert.assertFalse(event.getAfter().isPresent());
+ Assert.assertTrue(event.getBefore().isPresent());
+ }
+
+ @Test
+ public void testConstructor_nodeUpdated() {
+ Node node = new NodeBuilder().setKey(NODE_KEY)
+ .addAugmentation(NetconfNode.class, NETCONF_NODE_AUG_CONNECTED)
+ .build();
+ NodeOperEvent event = new NodeOperEvent(NODE_IID, node, node);
+ Assert.assertTrue(event.getAfter().isPresent());
+ Assert.assertTrue(event.getBefore().isPresent());
+ }
+
+ @Test
+ public void testConstructor_beforeNodeMissingNetconfNodeAug_Exception() {
+ Node node = new NodeBuilder().setKey(NODE_KEY).build();
+ thrown.expect(IllegalArgumentException.class);
+ new NodeOperEvent(NODE_IID, node, null);
+ }
+
+ @Test
+ public void testConstructor_afterNodeMissingNetconfNodeAug_Exception() {
+ Node node = new NodeBuilder().setKey(NODE_KEY).build();
+ thrown.expect(IllegalArgumentException.class);
+ new NodeOperEvent(NODE_IID, null, node);
+ }
+
+ @Test
+ public void testConstructor_nullNodes_Exception() {
+ thrown.expect(IllegalArgumentException.class);
+ new NodeOperEvent(NODE_IID, null, null);
+ }
+
+ @Test
+ public void testConstructor_nullIid_Exception() {
+ Node node = new NodeBuilder().setKey(NODE_KEY)
+ .addAugmentation(NetconfNode.class, NETCONF_NODE_AUG_CONNECTED)
+ .build();
+ thrown.expect(NullPointerException.class);
+ new NodeOperEvent(null, node, node);
+ }
+
+ @Test
+ public void testIsAfterConnected() {
+ Node node = new NodeBuilder().setKey(NODE_KEY)
+ .addAugmentation(NetconfNode.class, NETCONF_NODE_AUG_CONNECTED)
+ .build();
+ NodeOperEvent event = new NodeOperEvent(NODE_IID, null, node);
+ Assert.assertTrue(event.isAfterConnected());
+ }
+
+ @Test
+ public void testIsBeforeConnected() {
+ Node node = new NodeBuilder().setKey(NODE_KEY)
+ .addAugmentation(NetconfNode.class, NETCONF_NODE_AUG_CONNECTED)
+ .build();
+ NodeOperEvent event = new NodeOperEvent(NODE_IID, node, null);
+ Assert.assertTrue(event.isBeforeConnected());
+ }
+
+ @Test
+ public void testIsAfterConnected_false() {
+ Node node = new NodeBuilder().setKey(NODE_KEY)
+ .addAugmentation(NetconfNode.class, NETCONF_NODE_AUG_CONNECTING)
+ .build();
+ NodeOperEvent event = new NodeOperEvent(NODE_IID, null, node);
+ Assert.assertFalse(event.isAfterConnected());
+ }
+
+ @Test
+ public void testIsBeforeConnected_false() {
+ Node node = new NodeBuilder().setKey(NODE_KEY)
+ .addAugmentation(NetconfNode.class, NETCONF_NODE_AUG_CONNECTING)
+ .build();
+ NodeOperEvent event = new NodeOperEvent(NODE_IID, null, node);
+ Assert.assertFalse(event.isBeforeConnected());
+ }
+
+}
--- /dev/null
+/*
+ * Copyright (c) 2016 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.groupbasedpolicy.renderer.vpp.event;
+
+import org.junit.Assert;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.ContextId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.forwarding.rev160427.AddressType;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.forwarding.rev160427.ContextType;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.vpp_renderer.rev160425.Config;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.vpp_renderer.rev160425.config.VppEndpoint;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.vpp_renderer.rev160425.config.VppEndpointBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.vpp_renderer.rev160425.config.VppEndpointKey;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+public class VppEndpointConfEventTest {
+
+ private final static String ADDRESS = "1.1.1.1/32";
+ private final static ContextId CONTEXT_ID = new ContextId("ctx1");
+ private final static VppEndpointKey BASIC_VPP_EP_KEY =
+ new VppEndpointKey(ADDRESS, AddressType.class, CONTEXT_ID, ContextType.class);
+ private final static InstanceIdentifier<VppEndpoint> BASIC_VPP_EP_IID =
+ InstanceIdentifier.builder(Config.class).child(VppEndpoint.class, BASIC_VPP_EP_KEY).build();
+
+ @Rule
+ public ExpectedException thrown = ExpectedException.none();
+
+ @Test
+ public void testConstructor_vppEpCreated() {
+ VppEndpoint vppEndpoint = basicVppEpBuilder().build();
+ VppEndpointConfEvent event = new VppEndpointConfEvent(BASIC_VPP_EP_IID, null, vppEndpoint);
+ Assert.assertTrue(event.getAfter().isPresent());
+ Assert.assertFalse(event.getBefore().isPresent());
+ }
+
+ @Test
+ public void testConstructor_vppEpDeleted() {
+ VppEndpoint vppEndpoint = basicVppEpBuilder().build();
+ VppEndpointConfEvent event = new VppEndpointConfEvent(BASIC_VPP_EP_IID, vppEndpoint, null);
+ Assert.assertFalse(event.getAfter().isPresent());
+ Assert.assertTrue(event.getBefore().isPresent());
+ }
+
+ @Test
+ public void testConstructor_vppEpUpdated() {
+ VppEndpoint vppEndpoint = basicVppEpBuilder().build();
+ VppEndpointConfEvent event = new VppEndpointConfEvent(BASIC_VPP_EP_IID, vppEndpoint, vppEndpoint);
+ Assert.assertTrue(event.getAfter().isPresent());
+ Assert.assertTrue(event.getBefore().isPresent());
+ }
+
+ @Test
+ public void testConstructor_nullVppEp_Exception() {
+ thrown.expect(IllegalArgumentException.class);
+ new VppEndpointConfEvent(BASIC_VPP_EP_IID, null, null);
+ }
+
+ private VppEndpointBuilder basicVppEpBuilder() {
+ return new VppEndpointBuilder().setAddress(ADDRESS)
+ .setAddressType(AddressType.class)
+ .setContextId(CONTEXT_ID)
+ .setContextType(ContextType.class);
+ }
+
+}
--- /dev/null
+/*
+ * Copyright (c) 2016 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.groupbasedpolicy.renderer.vpp.iface;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.List;
+
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mockito;
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.groupbasedpolicy.renderer.vpp.event.VppEndpointConfEvent;
+import org.opendaylight.groupbasedpolicy.renderer.vpp.util.MountedDataBrokerProvider;
+import org.opendaylight.groupbasedpolicy.test.CustomDataBrokerTest;
+import org.opendaylight.groupbasedpolicy.util.IidFactory;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.Interfaces;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.InterfaceKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.ContextId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint_location_provider.rev160419.LocationProviders;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint_location_provider.rev160419.location.providers.LocationProvider;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint_location_provider.rev160419.location.providers.location.provider.ProviderAddressEndpointLocation;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.forwarding.rev160427.AddressType;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.forwarding.rev160427.ContextType;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.vpp_renderer.rev160425.Config;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.vpp_renderer.rev160425.config.VppEndpoint;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.vpp_renderer.rev160425.config.VppEndpointBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.vpp_renderer.rev160425.config.VppEndpointKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.vpp_renderer.rev160425.config.vpp.endpoint._interface.type.choice.VhostUserCaseBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VhostUser;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VhostUserRole;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VppInterfaceAugmentation;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces._interface.L2;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.l2.attributes.Interconnection;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.l2.attributes.interconnection.BridgeBased;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.BridgeDomains;
+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.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.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 com.google.common.base.Optional;
+import com.google.common.base.Strings;
+
+public class InterfaceManagerTest extends CustomDataBrokerTest {
+
+ private final static String ADDRESS = "1.1.1.1/32";
+ private final static ContextId CONTEXT_ID = new ContextId("ctx1");
+ private final static String IFACE_NAME = "ifaceName1";
+ private final static VppEndpointKey BASIC_VPP_EP_KEY =
+ new VppEndpointKey(ADDRESS, AddressType.class, CONTEXT_ID, ContextType.class);
+ private final static InstanceIdentifier<VppEndpoint> BASIC_VPP_EP_IID =
+ InstanceIdentifier.builder(Config.class).child(VppEndpoint.class, BASIC_VPP_EP_KEY).build();
+ private final static TopologyKey TOPO_KEY = new TopologyKey(new TopologyId("topo1"));
+ private final static NodeKey NODE_KEY = new NodeKey(new NodeId("node1"));
+ private final static InstanceIdentifier<Node> NODE_IID = InstanceIdentifier.builder(NetworkTopology.class)
+ .child(Topology.class, TOPO_KEY)
+ .child(Node.class, NODE_KEY)
+ .build();
+ private final static String SOCKET = "socket1";
+
+ private InterfaceManager manager;
+ private MountedDataBrokerProvider mountedDataProviderMock;
+ private DataBroker mountPointDataBroker;
+ private DataBroker dataBroker;
+
+ @Override
+ public Collection<Class<?>> getClassesFromModules() {
+ return Arrays.asList(Node.class, VppEndpoint.class, Interfaces.class, BridgeDomains.class,
+ LocationProviders.class);
+ }
+
+ @Before
+ public void init() throws Exception {
+ mountedDataProviderMock = Mockito.mock(MountedDataBrokerProvider.class);
+ mountPointDataBroker = getDataBroker();
+ setup(); // initialize new data broker for ODL data store
+ dataBroker = getDataBroker();
+ Mockito.when(mountedDataProviderMock.getDataBrokerForMountPoint(Mockito.any(InstanceIdentifier.class)))
+ .thenReturn(Optional.of(mountPointDataBroker));
+ manager = new InterfaceManager(mountedDataProviderMock, dataBroker);
+ }
+
+ @Test
+ public void testVppEndpointChanged_created() throws Exception {
+ VppEndpoint vhostEp = vhostVppEpBuilder().build();
+ VppEndpointConfEvent event = new VppEndpointConfEvent(BASIC_VPP_EP_IID, null, vhostEp);
+
+ manager.vppEndpointChanged(event);
+ // assert state on data store behind mount point
+ ReadOnlyTransaction rTxMount = mountPointDataBroker.newReadOnlyTransaction();
+ Optional<Interface> potentialIface =
+ rTxMount.read(LogicalDatastoreType.CONFIGURATION, InstanceIdentifier.builder(Interfaces.class)
+ .child(Interface.class, new InterfaceKey(vhostEp.getVppInterfaceName()))
+ .build()).get();
+ Assert.assertTrue(potentialIface.isPresent());
+ Interface iface = potentialIface.get();
+ Assert.assertEquals(VhostUser.class, iface.getType());
+ Assert.assertTrue(iface.isEnabled());
+ VppInterfaceAugmentation vppIface = iface.getAugmentation(VppInterfaceAugmentation.class);
+ Assert.assertNotNull(vppIface);
+ org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces._interface.VhostUser vhostUserIface =
+ vppIface.getVhostUser();
+ Assert.assertNotNull(vhostUserIface);
+ Assert.assertEquals(VhostUserRole.Client, vhostUserIface.getRole());
+ Assert.assertEquals(SOCKET, vhostUserIface.getSocket());
+ L2 l2Iface = vppIface.getL2();
+ if (l2Iface != null) {
+ Interconnection interconnection = l2Iface.getInterconnection();
+ if (interconnection != null) {
+ if (interconnection instanceof BridgeBased) {
+ BridgeBased bridgeL2Iface = (BridgeBased) interconnection;
+ Assert.assertTrue(Strings.isNullOrEmpty(bridgeL2Iface.getBridgeDomain()));
+ }
+ }
+ }
+ // assert state on ODL data store
+ ReadOnlyTransaction rTx = dataBroker.newReadOnlyTransaction();
+ Optional<LocationProvider> optLocationProvider = rTx.read(LogicalDatastoreType.CONFIGURATION, IidFactory.locationProviderIid(VppEndpointLocationProvider.VPP_ENDPOINT_LOCATION_PROVIDER)).get();
+ Assert.assertTrue(optLocationProvider.isPresent());
+ List<ProviderAddressEndpointLocation> epLocs = optLocationProvider.get().getProviderAddressEndpointLocation();
+ Assert.assertNotNull(epLocs);
+ Assert.assertEquals(1, epLocs.size());
+ ProviderAddressEndpointLocation epLoc = VppEndpointLocationProvider.createProviderAddressEndpointLocation(vhostEp);
+ Assert.assertEquals(epLoc, epLocs.get(0));
+ }
+
+ @Test
+ public void testVppEndpointChanged_deleted() throws Exception {
+ VppEndpoint vhostEp = vhostVppEpBuilder().build();
+ VppEndpointConfEvent createVppEpEvent = new VppEndpointConfEvent(BASIC_VPP_EP_IID, null, vhostEp);
+ VppEndpointConfEvent deleteVppEpEvent = new VppEndpointConfEvent(BASIC_VPP_EP_IID, vhostEp, null);
+
+ manager.vppEndpointChanged(createVppEpEvent);
+ manager.vppEndpointChanged(deleteVppEpEvent);
+ // assert state on data store behind mount point
+ ReadOnlyTransaction rTxMount = mountPointDataBroker.newReadOnlyTransaction();
+ Optional<Interface> potentialIface =
+ rTxMount.read(LogicalDatastoreType.CONFIGURATION, InstanceIdentifier.builder(Interfaces.class)
+ .child(Interface.class, new InterfaceKey(vhostEp.getVppInterfaceName()))
+ .build()).get();
+ Assert.assertFalse(potentialIface.isPresent());
+ // assert state on ODL data store
+ ReadOnlyTransaction rTx = dataBroker.newReadOnlyTransaction();
+ ProviderAddressEndpointLocation providerAddressEndpointLocation =
+ VppEndpointLocationProvider.createProviderAddressEndpointLocation(vhostEp);
+ InstanceIdentifier<ProviderAddressEndpointLocation> providerAddressEndpointLocationIid = IidFactory
+ .providerAddressEndpointLocationIid(VppEndpointLocationProvider.VPP_ENDPOINT_LOCATION_PROVIDER,
+ providerAddressEndpointLocation.getKey());
+ Optional<ProviderAddressEndpointLocation> optProvEpLoc =
+ rTx.read(LogicalDatastoreType.CONFIGURATION, providerAddressEndpointLocationIid).get();
+ Assert.assertFalse(optProvEpLoc.isPresent());
+ }
+
+ private VppEndpointBuilder vhostVppEpBuilder() {
+ return basicVppEpBuilder().setVppInterfaceName(IFACE_NAME)
+ .setVppNodePath(NODE_IID)
+ .setInterfaceTypeChoice(new VhostUserCaseBuilder().setSocket(SOCKET).build());
+ }
+
+ private VppEndpointBuilder basicVppEpBuilder() {
+ return new VppEndpointBuilder().setAddress(ADDRESS)
+ .setAddressType(AddressType.class)
+ .setContextId(CONTEXT_ID)
+ .setContextType(ContextType.class);
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2016 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.groupbasedpolicy.renderer.vpp.listener;
+
+import java.util.Arrays;
+import java.util.Collection;
+
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mockito;
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.groupbasedpolicy.renderer.vpp.event.VppEndpointConfEvent;
+import org.opendaylight.groupbasedpolicy.test.CustomDataBrokerTest;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.ContextId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint_location_provider.rev160419.LocationProviders;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.forwarding.rev160427.AddressType;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.forwarding.rev160427.ContextType;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.forwarding.rev160427.Forwarding;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.vpp_renderer.rev160425.Config;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.vpp_renderer.rev160425.config.VppEndpoint;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.vpp_renderer.rev160425.config.VppEndpointBuilder;
+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 com.google.common.base.Optional;
+import com.google.common.eventbus.EventBus;
+
+public class VppEndpointListenerTest extends CustomDataBrokerTest {
+
+ private final static String ADDRESS = "1.1.1.1/32";
+ private final static ContextId CONTEXT_ID = new ContextId("ctx1");
+ private final static String IFACE_NAME = "ifaceName";
+
+ private DataBroker dataBroker;
+ private VppEndpointListener listener;
+ private EventBus eventBusMock;
+
+ @Override
+ public Collection<Class<?>> getClassesFromModules() {
+ return Arrays.asList(Node.class, VppEndpoint.class, Forwarding.class, LocationProviders.class);
+ }
+
+ @Before
+ public void init() {
+ dataBroker = getDataBroker();
+ eventBusMock = Mockito.mock(EventBus.class);
+ listener = new VppEndpointListener(dataBroker, eventBusMock);
+ }
+
+ @Test
+ public void testOnWrite() throws Exception {
+ ArgumentCaptor<VppEndpointConfEvent> argVppEpEvent = ArgumentCaptor.forClass(VppEndpointConfEvent.class);
+ VppEndpoint vppEndpoint = new VppEndpointBuilder().setAddress(ADDRESS)
+ .setAddressType(AddressType.class)
+ .setContextId(CONTEXT_ID)
+ .setContextType(ContextType.class)
+ .build();
+ InstanceIdentifier<VppEndpoint> vppEpIid =
+ InstanceIdentifier.builder(Config.class).child(VppEndpoint.class, vppEndpoint.getKey()).build();
+ WriteTransaction wTx = getDataBroker().newWriteOnlyTransaction();
+ wTx.put(LogicalDatastoreType.CONFIGURATION, vppEpIid, vppEndpoint);
+ wTx.submit().get();
+
+ Mockito.verify(eventBusMock).post(argVppEpEvent.capture());
+ VppEndpointConfEvent capturedVppEpEvent = argVppEpEvent.getValue();
+ Assert.assertEquals(vppEpIid, capturedVppEpEvent.getIid());
+ assertEqualsOptional(null, capturedVppEpEvent.getBefore());
+ assertEqualsOptional(vppEndpoint, capturedVppEpEvent.getAfter());
+ }
+
+ @Test
+ public void testOnDelete() throws Exception {
+ ArgumentCaptor<VppEndpointConfEvent> argVppEpEvent = ArgumentCaptor.forClass(VppEndpointConfEvent.class);
+ VppEndpoint vppEndpoint = new VppEndpointBuilder().setAddress(ADDRESS)
+ .setAddressType(AddressType.class)
+ .setContextId(CONTEXT_ID)
+ .setContextType(ContextType.class)
+ .build();
+ InstanceIdentifier<VppEndpoint> vppEpIid =
+ InstanceIdentifier.builder(Config.class).child(VppEndpoint.class, vppEndpoint.getKey()).build();
+ WriteTransaction wTx = getDataBroker().newWriteOnlyTransaction();
+ wTx.put(LogicalDatastoreType.CONFIGURATION, vppEpIid, vppEndpoint);
+ wTx.submit().get();
+ wTx = getDataBroker().newWriteOnlyTransaction();
+ wTx.delete(LogicalDatastoreType.CONFIGURATION, vppEpIid);
+ wTx.submit().get();
+
+ Mockito.verify(eventBusMock, Mockito.times(2)).post(argVppEpEvent.capture());
+ VppEndpointConfEvent capturedVppEpEvent = argVppEpEvent.getAllValues().get(1);
+ Assert.assertEquals(vppEpIid, capturedVppEpEvent.getIid());
+ assertEqualsOptional(vppEndpoint, capturedVppEpEvent.getBefore());
+ assertEqualsOptional(null, capturedVppEpEvent.getAfter());
+ }
+
+ @Test
+ public void testOnSubtreeModified() throws Exception {
+ ArgumentCaptor<VppEndpointConfEvent> argVppEpEvent = ArgumentCaptor.forClass(VppEndpointConfEvent.class);
+ VppEndpointBuilder vppEndpointBuilder = new VppEndpointBuilder().setAddress(ADDRESS)
+ .setAddressType(AddressType.class)
+ .setContextId(CONTEXT_ID)
+ .setContextType(ContextType.class);
+ VppEndpoint vppEndpoint = vppEndpointBuilder.build();
+ InstanceIdentifier<VppEndpoint> vppEpIid =
+ InstanceIdentifier.builder(Config.class).child(VppEndpoint.class, vppEndpoint.getKey()).build();
+ WriteTransaction wTx = getDataBroker().newWriteOnlyTransaction();
+ wTx.put(LogicalDatastoreType.CONFIGURATION, vppEpIid, vppEndpoint);
+ wTx.submit().get();
+ VppEndpoint modifiedVppEndpoint = vppEndpointBuilder.setVppInterfaceName(IFACE_NAME).build();
+ wTx = getDataBroker().newWriteOnlyTransaction();
+ wTx.put(LogicalDatastoreType.CONFIGURATION, vppEpIid, modifiedVppEndpoint);
+ wTx.submit().get();
+
+ Mockito.verify(eventBusMock, Mockito.times(2)).post(argVppEpEvent.capture());
+ VppEndpointConfEvent capturedFirstVppEpEvent = argVppEpEvent.getAllValues().get(0);
+ Assert.assertEquals(vppEpIid, capturedFirstVppEpEvent.getIid());
+ assertEqualsOptional(null, capturedFirstVppEpEvent.getBefore());
+ assertEqualsOptional(vppEndpoint, capturedFirstVppEpEvent.getAfter());
+ VppEndpointConfEvent capturedSecondVppEpEvent = argVppEpEvent.getAllValues().get(1);
+ Assert.assertEquals(vppEpIid, capturedSecondVppEpEvent.getIid());
+ assertEqualsOptional(vppEndpoint, capturedSecondVppEpEvent.getBefore());
+ assertEqualsOptional(modifiedVppEndpoint, capturedSecondVppEpEvent.getAfter());
+ }
+
+ private <T> void assertEqualsOptional(T expected, Optional<T> actual) {
+ if (expected == null) {
+ Assert.assertFalse(actual.isPresent());
+ } else {
+ Assert.assertTrue(actual.isPresent());
+ Assert.assertEquals(expected, actual.get());
+ }
+ }
+
+}
package org.opendaylight.groupbasedpolicy.renderer.vpp.manager;
import com.google.common.base.Optional;
+import com.google.common.eventbus.EventBus;
import com.google.common.util.concurrent.CheckedFuture;
import org.junit.After;
import org.junit.Assert;
Mockito.when(mountPoint.getService(Matchers.<Class<DataBroker>>any())).thenReturn(Optional.of(dataBroker2));
dataBroker = getDataBroker();
vppNodeManager = new VppNodeManager(dataBroker, providerContext);
- vppNodeListener = new VppNodeListener(dataBroker, vppNodeManager);
+ vppNodeListener = new VppNodeListener(dataBroker, vppNodeManager, new EventBus());
}
private Node createNode(final String name, NetconfNodeConnectionStatus.ConnectionStatus status) {