diff options
author | Jozef Gloncak <jgloncak@cisco.com> | 2016-02-08 15:12:14 +0100 |
---|---|---|
committer | Gerrit Code Review <gerrit@fd.io> | 2016-02-08 21:57:19 +0000 |
commit | b46f6ad9d5cf138d9b4cba9c03dc09aea450e94a (patch) | |
tree | faeb85e7d2a6f1baa83343b42adcfe9343b64a83 | |
parent | 37c09259c1958fe5ed7c28bc24f593577070bbcb (diff) |
Code refactor - standalone class for Vpp manipulation.
Change-Id: I3869462364f2a73177eca6848bac897ccadfd67f
Signed-off-by: Jozef Gloncak <jgloncak@cisco.com>
-rw-r--r-- | vbd/impl/src/main/java/io/fd/honeycomb/vbd/impl/BridgeDomain.java | 165 | ||||
-rw-r--r-- | vbd/impl/src/main/java/io/fd/honeycomb/vbd/impl/VppModifier.java | 204 |
2 files changed, 228 insertions, 141 deletions
diff --git a/vbd/impl/src/main/java/io/fd/honeycomb/vbd/impl/BridgeDomain.java b/vbd/impl/src/main/java/io/fd/honeycomb/vbd/impl/BridgeDomain.java index bb1a5b0c3..0ecd14c1e 100644 --- a/vbd/impl/src/main/java/io/fd/honeycomb/vbd/impl/BridgeDomain.java +++ b/vbd/impl/src/main/java/io/fd/honeycomb/vbd/impl/BridgeDomain.java @@ -16,7 +16,6 @@ import com.google.common.util.concurrent.CheckedFuture; import com.google.common.util.concurrent.FutureCallback; import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.ListenableFuture; -import com.google.common.util.concurrent.SettableFuture; import java.util.ArrayList; import java.util.Collection; import java.util.List; @@ -32,28 +31,18 @@ import org.opendaylight.controller.md.sal.binding.api.DataTreeIdentifier; import org.opendaylight.controller.md.sal.binding.api.DataTreeModification; import org.opendaylight.controller.md.sal.binding.api.MountPoint; import org.opendaylight.controller.md.sal.binding.api.MountPointService; -import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction; 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.ReadFailedException; import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException; import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv4AddressNoZone; 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.InterfaceBuilder; import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.InterfaceKey; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.Interface1; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces._interface.Ipv4; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces._interface.ipv4.Address; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.external.reference.rev160129.ExternalReference; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.Vpp; 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.VppInterfaceAugmentationBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VxlanTunnel; 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.interfaces._interface.L2Builder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces._interface.Vxlan; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces._interface.VxlanBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces._interface.l2.interconnection.BridgeBasedBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.BridgeDomains; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.bridge.domains.BridgeDomainBuilder; @@ -64,7 +53,6 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vbridge. import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vbridge.topology.rev160129.TerminationPointVbridgeAugment; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vbridge.topology.rev160129.TerminationPointVbridgeAugmentBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vbridge.topology.rev160129.TopologyVbridgeAugment; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vbridge.topology.rev160129.network.topology.topology.TunnelParameters; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vbridge.topology.rev160129.network.topology.topology.node.BridgeMember; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vbridge.topology.rev160129.network.topology.topology.node.BridgeMemberBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vbridge.topology.rev160129.network.topology.topology.node.termination.point.InterfaceType; @@ -100,23 +88,22 @@ import org.slf4j.LoggerFactory; */ final class BridgeDomain implements DataTreeChangeListener<Topology> { private static final Logger LOG = LoggerFactory.getLogger(BridgeDomain.class); + private static final int SOURCE_VPP_INDEX = 0; private static final int DESTINATION_VPP_INDEX = 1; private static final String TUNNEL_ID_PREFIX = "vxlan_tunnel"; - private static final String TUNNEL_DESCRIPTION = "virtual interface which interconnects VPPs"; - private static final Long DEFAULT_ENCAP_VRF_ID = 0L; - private static final String TUNNEL_ID_DEMO = TUNNEL_ID_PREFIX + "0"; + static final String TUNNEL_ID_DEMO = TUNNEL_ID_PREFIX + "0"; private final KeyedInstanceIdentifier<Topology, TopologyKey> topology; @GuardedBy("this") private final BindingTransactionChain chain; private final ListenerRegistration<?> reg; private final MountPointService mountService; + private final VppModifier vppModifier; private TopologyVbridgeAugment config; private final String bridgeDomainName; private final InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.bridge.domains.BridgeDomain> iiBridgeDomainOnVPP; private final String iiBridgeDomainOnVPPRest; - private final DataBroker dataBroker; private Multimap<NodeId, KeyedInstanceIdentifier<Node, NodeKey>> nodesToVpps = ArrayListMultimap.create(); private final List<Integer> tunnelIds; @@ -132,10 +119,10 @@ final class BridgeDomain implements DataTreeChangeListener<Topology> { .child(BridgeDomains.class) .child(org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.bridge.domains.BridgeDomain.class, new BridgeDomainKey(bridgeDomainName)); - this.dataBroker = dataBroker; reg = dataBroker.registerDataTreeChangeListener( - new DataTreeIdentifier<>(LogicalDatastoreType.CONFIGURATION, topology), this); + new DataTreeIdentifier<>(LogicalDatastoreType.CONFIGURATION, topology), this); this.tunnelIds = new ArrayList<>(); + this.vppModifier = new VppModifier(mountService); } private String provideIIBrdigeDomainOnVPPRest() { @@ -210,6 +197,7 @@ final class BridgeDomain implements DataTreeChangeListener<Topology> { // Read configuration final TopologyVbridgeAugment config = data.getAugmentation(TopologyVbridgeAugment.class); + vppModifier.setConfig(config); if (config != null) { setConfiguration(config); } else { @@ -256,93 +244,38 @@ final class BridgeDomain implements DataTreeChangeListener<Topology> { } } - private void addTunnel(final NodeId newNode) { - for (Map.Entry<NodeId, KeyedInstanceIdentifier<Node, NodeKey>> entryToVpp : nodesToVpps.entries()) { - if (!entryToVpp.getKey().equals(newNode)) { + private void addTunnel(final NodeId sourceNode) { + final KeyedInstanceIdentifier<Node, NodeKey> iiToSrcVpp = nodesToVpps.get(sourceNode).iterator().next(); + for (Map.Entry<NodeId, KeyedInstanceIdentifier<Node, NodeKey>> nodeToVpp : nodesToVpps.entries()) { + if (!nodeToVpp.getKey().equals(sourceNode)) { //TODO: check whether returned value from nodesToVpps is not null - final KeyedInstanceIdentifier<Node, NodeKey> iiToOldVpp = entryToVpp.getValue(); - final KeyedInstanceIdentifier<Node, NodeKey> iiToNewVpp = nodesToVpps.get(newNode).iterator().next(); - final NodeId oldNode = entryToVpp.getKey(); + final KeyedInstanceIdentifier<Node, NodeKey> iiToDstVpp = nodeToVpp.getValue(); + final NodeId dstNode = nodeToVpp.getKey(); - final ListenableFuture<List<Optional<Ipv4AddressNoZone>>> ipAddressesFuture = readIpAddressesFromVpps(iiToOldVpp, iiToNewVpp); + final ListenableFuture<List<Optional<Ipv4AddressNoZone>>> ipAddressesFuture = vppModifier.readIpAddressesFromVpps(iiToDstVpp, iiToSrcVpp); Futures.addCallback(ipAddressesFuture, new FutureCallback<List<Optional<Ipv4AddressNoZone>>>() { @Override public void onSuccess(List<Optional<Ipv4AddressNoZone>> ipAddresses) { if (ipAddresses.size() == 2) { LOG.debug("All required IP addresses for creating tunnel were obtained."); - final Optional<Ipv4AddressNoZone> ipAddressNewVpp = ipAddresses.get(SOURCE_VPP_INDEX); - final Optional<Ipv4AddressNoZone> ipAddressOldVpp = ipAddresses.get(DESTINATION_VPP_INDEX); - if (ipAddressNewVpp != null && ipAddressOldVpp != null) { - if (ipAddressNewVpp.isPresent() && ipAddressOldVpp.isPresent()) { - //writing v3po:vxlan container to new node - Vxlan vxlanData = prepareVxlan(ipAddressOldVpp.get(), ipAddressNewVpp.get()); - Interface intfData = prepareVirtualInterfaceData(vxlanData); - createVirtualInterfaceOnVpp(intfData, iiToNewVpp); + final Optional<Ipv4AddressNoZone> ipAddressSrcVpp = ipAddresses.get(SOURCE_VPP_INDEX); + final Optional<Ipv4AddressNoZone> ipAddressDstVpp = ipAddresses.get(DESTINATION_VPP_INDEX); + if (ipAddressSrcVpp != null && ipAddressDstVpp != null) { + if (ipAddressSrcVpp.isPresent() && ipAddressDstVpp.isPresent()) { + //writing v3po:vxlan container to source node + vppModifier.createVirtualInterfaceOnVpp(ipAddressSrcVpp.get(), ipAddressDstVpp.get(), iiToSrcVpp); //writing v3po:vxlan container to existing node - vxlanData = prepareVxlan(ipAddressNewVpp.get(), ipAddressOldVpp.get()); - intfData = prepareVirtualInterfaceData(vxlanData); - createVirtualInterfaceOnVpp(intfData, iiToOldVpp); + vppModifier.createVirtualInterfaceOnVpp(ipAddressDstVpp.get(), ipAddressSrcVpp.get(), iiToDstVpp); - addTerminationPoint(topology.child(Node.class, new NodeKey(oldNode))); - addTerminationPoint(topology.child(Node.class, new NodeKey(newNode))); + addTerminationPoint(topology.child(Node.class, new NodeKey(dstNode))); + addTerminationPoint(topology.child(Node.class, new NodeKey(sourceNode))); - addLinkBetweenTerminationPoints(newNode, oldNode); - addLinkBetweenTerminationPoints(oldNode, newNode); + addLinkBetweenTerminationPoints(sourceNode, dstNode); + addLinkBetweenTerminationPoints(dstNode, sourceNode); } } } - - } - - private void createVirtualInterfaceOnVpp(final Interface intfData, final KeyedInstanceIdentifier<Node, NodeKey> iiToVpp) { - final DataBroker vppDataBroker = resolveDataBrokerForMountPoint(iiToVpp); - if (vppDataBroker != null) { - final WriteTransaction wTx = vppDataBroker.newWriteOnlyTransaction(); - final KeyedInstanceIdentifier<Interface, InterfaceKey> iiToInterface - = InstanceIdentifier.create(Interfaces.class).child(Interface.class, new InterfaceKey(TUNNEL_ID_DEMO)); - wTx.put(LogicalDatastoreType.CONFIGURATION, iiToInterface, intfData); - final CheckedFuture<Void, TransactionCommitFailedException> submitFuture = wTx.submit(); - Futures.addCallback(submitFuture, new FutureCallback<Void>() { - @Override - public void onSuccess(@Nullable Void result) { - LOG.debug("Writing super virtual interface to {} finished successfully.",iiToVpp.getKey().getNodeId()); - } - - @Override - public void onFailure(Throwable t) { - LOG.debug("Writing super virtual interface to {} failed.",iiToVpp.getKey().getNodeId()); - } - }); - } else { - LOG.debug("Writing virtual interface {} to VPP {} wasn't successfull because missing data broker.",TUNNEL_DESCRIPTION, iiToVpp); - } - } - - private Interface prepareVirtualInterfaceData(final Vxlan vxlan) { - final InterfaceBuilder interfaceBuilder = new InterfaceBuilder(); - //TODO implement tunnel counter - interfaceBuilder.setName(TUNNEL_ID_DEMO); - interfaceBuilder.setType(VxlanTunnel.class); - VppInterfaceAugmentationBuilder vppInterfaceAugmentationBuilder = new VppInterfaceAugmentationBuilder(); - vppInterfaceAugmentationBuilder.setVxlan(vxlan); - interfaceBuilder.addAugmentation(VppInterfaceAugmentation.class, vppInterfaceAugmentationBuilder.build()); - return interfaceBuilder.build(); - } - - private Vxlan prepareVxlan(final Ipv4AddressNoZone ipSrc, final Ipv4AddressNoZone ipDst) { - final VxlanBuilder vxlanBuilder = new VxlanBuilder(); - vxlanBuilder.setSrc(ipSrc); - vxlanBuilder.setDst(ipDst); - final TunnelParameters tunnelParameters = config.getTunnelParameters(); - if (tunnelParameters instanceof org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vbridge.topology.rev160129.network.topology.topology.tunnel.parameters.Vxlan) { - org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vbridge.topology.rev160129.network.topology.topology.tunnel.parameters.Vxlan vxlan = - (org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vbridge.topology.rev160129.network.topology.topology.tunnel.parameters.Vxlan) tunnelParameters; - //TODO: handle NPE - vxlanBuilder.setVni(vxlan.getVxlan().getVni()); - } - vxlanBuilder.setEncapVrfId(DEFAULT_ENCAP_VRF_ID); - return vxlanBuilder.build(); } @Override @@ -362,7 +295,6 @@ final class BridgeDomain implements DataTreeChangeListener<Topology> { final WriteTransaction wTx = chain.newWriteOnlyTransaction(); wTx.put(LogicalDatastoreType.OPERATIONAL, iiToLink, prepareData(newVpp, odlVpp, linkId),true); wTx.submit(); - } private Link prepareData(final NodeId newVpp, final NodeId oldVpp, final LinkId linkId) { @@ -374,7 +306,6 @@ final class BridgeDomain implements DataTreeChangeListener<Topology> { sourceBuilder.setSourceTp(new TpId(TUNNEL_ID_DEMO)); linkBuilder.setSource(sourceBuilder.build()); - final DestinationBuilder destinationBuilder = new DestinationBuilder(); destinationBuilder.setDestNode(oldVpp); destinationBuilder.setDestTp(new TpId(TUNNEL_ID_DEMO)); @@ -386,54 +317,6 @@ final class BridgeDomain implements DataTreeChangeListener<Topology> { return linkBuilder.build(); } - private ListenableFuture<List<Optional<Ipv4AddressNoZone>>> readIpAddressesFromVpps(final KeyedInstanceIdentifier<Node, NodeKey>... iiToVpps) { - final List<ListenableFuture<Optional<Ipv4AddressNoZone>>> ipv4Futures = new ArrayList<>(); - for (final KeyedInstanceIdentifier<Node, NodeKey> iiToVpp : iiToVpps) { - ipv4Futures.add(readIpAddressFromVpp(iiToVpp)); - } - return Futures.successfulAsList(ipv4Futures); - } - - private ListenableFuture<Optional<Ipv4AddressNoZone>> readIpAddressFromVpp(final KeyedInstanceIdentifier<Node, NodeKey> iiToVpp) { - final SettableFuture<Optional<Ipv4AddressNoZone>> resultFuture = SettableFuture.create(); - - final DataBroker vppDataBroker = resolveDataBrokerForMountPoint(iiToVpp); - final ReadOnlyTransaction rTx = vppDataBroker.newReadOnlyTransaction(); - final CheckedFuture<Optional<Interfaces>, ReadFailedException> interfaceStateFuture - = rTx.read(LogicalDatastoreType.CONFIGURATION, InstanceIdentifier.create(Interfaces.class)); - - Futures.addCallback(interfaceStateFuture, new FutureCallback<Optional<Interfaces>>() { - @Override - public void onSuccess(Optional<Interfaces> optInterfaces) { - if (optInterfaces.isPresent()) { - for (org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface intf : optInterfaces.get().getInterface()) { - final Interface1 interface1 = intf.getAugmentation(Interface1.class); - if (interface1 != null) { - final Ipv4 ipv4 = interface1.getIpv4(); - if (ipv4 != null) { - final List<Address> addresses = ipv4.getAddress(); - if (!addresses.isEmpty()) { - final Ipv4AddressNoZone ip = addresses.iterator().next().getIp(); - if (ip != null) { - resultFuture.set(Optional.of(ip)); - break; - } - } - } - } - } - } - resultFuture.set(Optional.<Ipv4AddressNoZone>absent()); - } - - @Override - public void onFailure(Throwable t) { - resultFuture.setException(t); - - } - }); - return resultFuture; - } private void modifyTerminationPoint(final DataObjectModification<TerminationPoint> nodeChild, final NodeId nodeId) { diff --git a/vbd/impl/src/main/java/io/fd/honeycomb/vbd/impl/VppModifier.java b/vbd/impl/src/main/java/io/fd/honeycomb/vbd/impl/VppModifier.java new file mode 100644 index 000000000..142272b82 --- /dev/null +++ b/vbd/impl/src/main/java/io/fd/honeycomb/vbd/impl/VppModifier.java @@ -0,0 +1,204 @@ +/** + * Copyright (c) 2016 Cisco Systems, Inc. and others. All rights reserved. + * <p> + * 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 io.fd.honeycomb.vbd.impl; + +import com.google.common.base.Optional; +import com.google.common.util.concurrent.CheckedFuture; +import com.google.common.util.concurrent.FutureCallback; +import com.google.common.util.concurrent.Futures; +import com.google.common.util.concurrent.ListenableFuture; +import com.google.common.util.concurrent.SettableFuture; +import java.util.ArrayList; +import java.util.List; +import javax.annotation.Nullable; +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.controller.md.sal.binding.api.ReadOnlyTransaction; +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.ReadFailedException; +import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv4AddressNoZone; +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.InterfaceBuilder; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.InterfaceKey; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.Interface1; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces._interface.Ipv4; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces._interface.ipv4.Address; +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.VppInterfaceAugmentationBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VxlanTunnel; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces._interface.Vxlan; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces._interface.VxlanBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vbridge.topology.rev160129.TopologyVbridgeAugment; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vbridge.topology.rev160129.network.topology.topology.TunnelParameters; +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.opendaylight.yangtools.yang.binding.KeyedInstanceIdentifier; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Class which is used for manipulation with VPP + */ +public class VppModifier { + private static final Long DEFAULT_ENCAP_VRF_ID = 0L; + + private static final Logger LOG = LoggerFactory.getLogger(BridgeDomain.class); + private final MountPointService mountService; + private TopologyVbridgeAugment config; + + + public VppModifier(final MountPointService mountService) { + this.mountService = mountService; + } + /** + * Tryies to read ipv4 addresses from all specified {@code iiToVpps } vpps. + * + * @param iiToVpps collection of instance identifiers which points to concrete mount points. + * @return future which contains list of ip addreases in the same order as was specified in {@code iiToVpps} + */ + ListenableFuture<List<Optional<Ipv4AddressNoZone>>> readIpAddressesFromVpps(final KeyedInstanceIdentifier<Node, NodeKey>... iiToVpps) { + final List<ListenableFuture<Optional<Ipv4AddressNoZone>>> ipv4Futures = new ArrayList<>(); + for (final KeyedInstanceIdentifier<Node, NodeKey> iiToVpp : iiToVpps) { + ipv4Futures.add(readIpAddressFromVpp(iiToVpp)); + } + return Futures.successfulAsList(ipv4Futures); + } + + /** + * Passes through interfaces at mount point specified via {@code iiToVpp}. + * + * When first ipv4 address is found then it is returned. + * + * @param iiToVpp instance idenfifier which point to mounted vpp + * @return if set ipv4 address is found at mounted vpp then it is returned as future. Otherwise absent value is returned + * in future or exception which has been thrown + */ + private ListenableFuture<Optional<Ipv4AddressNoZone>> readIpAddressFromVpp(final KeyedInstanceIdentifier<Node, NodeKey> iiToVpp) { + final SettableFuture<Optional<Ipv4AddressNoZone>> resultFuture = SettableFuture.create(); + + final DataBroker vppDataBroker = resolveDataBrokerForMountPoint(iiToVpp); + if (vppDataBroker != null) { + final ReadOnlyTransaction rTx = vppDataBroker.newReadOnlyTransaction(); + final CheckedFuture<Optional<Interfaces>, ReadFailedException> interfaceStateFuture + = rTx.read(LogicalDatastoreType.CONFIGURATION, InstanceIdentifier.create(Interfaces.class)); + + Futures.addCallback(interfaceStateFuture, new FutureCallback<Optional<Interfaces>>() { + @Override + public void onSuccess(final Optional<Interfaces> optInterfaces) { + if (optInterfaces.isPresent()) { + for (org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface intf : optInterfaces.get().getInterface()) { + final Interface1 interface1 = intf.getAugmentation(Interface1.class); + if (interface1 != null) { + final Ipv4 ipv4 = interface1.getIpv4(); + if (ipv4 != null) { + final List<Address> addresses = ipv4.getAddress(); + if (!addresses.isEmpty()) { + final Ipv4AddressNoZone ip = addresses.iterator().next().getIp(); + if (ip != null) { + resultFuture.set(Optional.of(ip)); + break; + } + } + } + } + } + } else { + LOG.debug("There is no inferface with ipv4 address set at VPP {}.", iiToVpp); + resultFuture.set(Optional.<Ipv4AddressNoZone>absent()); + } + } + + @Override + public void onFailure(Throwable t) { + resultFuture.setException(t); + } + }); + } else { + LOG.debug("Data broker for vpp {} is missing.", iiToVpp); + resultFuture.set(Optional.<Ipv4AddressNoZone>absent()); + } + return resultFuture; + } + + void createVirtualInterfaceOnVpp(final Ipv4AddressNoZone ipSrc, final Ipv4AddressNoZone ipDst, final KeyedInstanceIdentifier<Node, NodeKey> iiToVpp) { + final Vxlan vxlanData = prepareVxlan(ipSrc, ipDst); + final Interface intfData = prepareVirtualInterfaceData(vxlanData); + + final DataBroker vppDataBroker = resolveDataBrokerForMountPoint(iiToVpp); + if (vppDataBroker != null) { + final WriteTransaction wTx = vppDataBroker.newWriteOnlyTransaction(); + final KeyedInstanceIdentifier<Interface, InterfaceKey> iiToInterface + = InstanceIdentifier.create(Interfaces.class).child(Interface.class, new InterfaceKey(BridgeDomain.TUNNEL_ID_DEMO)); + wTx.put(LogicalDatastoreType.CONFIGURATION, iiToInterface, intfData); + final CheckedFuture<Void, TransactionCommitFailedException> submitFuture = wTx.submit(); + Futures.addCallback(submitFuture, new FutureCallback<Void>() { + @Override + public void onSuccess(@Nullable Void result) { + LOG.debug("Writing super virtual interface to {} finished successfully.",iiToVpp.getKey().getNodeId()); + } + + @Override + public void onFailure(Throwable t) { + LOG.debug("Writing super virtual interface to {} failed.", iiToVpp.getKey().getNodeId()); + } + }); + } else { + LOG.debug("Writing virtual interface {} to VPP {} wasn't successfull because missing data broker.", BridgeDomain.TUNNEL_ID_DEMO, iiToVpp); + } + } + + + private DataBroker resolveDataBrokerForMountPoint(final InstanceIdentifier<Node> iiToMountPoint) { + final Optional<MountPoint> vppMountPointOpt = mountService.getMountPoint(iiToMountPoint); + if (vppMountPointOpt.isPresent()) { + final MountPoint vppMountPoint = vppMountPointOpt.get(); + final Optional<DataBroker> dataBrokerOpt = vppMountPoint.getService(DataBroker.class); + if (dataBrokerOpt.isPresent()) { + return dataBrokerOpt.get(); + } + } + return null; + } + + + private Interface prepareVirtualInterfaceData(final Vxlan vxlan) { + final InterfaceBuilder interfaceBuilder = new InterfaceBuilder(); + //TODO implement tunnel counter + interfaceBuilder.setName(BridgeDomain.TUNNEL_ID_DEMO); + interfaceBuilder.setType(VxlanTunnel.class); + VppInterfaceAugmentationBuilder vppInterfaceAugmentationBuilder = new VppInterfaceAugmentationBuilder(); + vppInterfaceAugmentationBuilder.setVxlan(vxlan); + interfaceBuilder.addAugmentation(VppInterfaceAugmentation.class, vppInterfaceAugmentationBuilder.build()); + return interfaceBuilder.build(); + } + + private Vxlan prepareVxlan(final Ipv4AddressNoZone ipSrc, final Ipv4AddressNoZone ipDst) { + final VxlanBuilder vxlanBuilder = new VxlanBuilder(); + vxlanBuilder.setSrc(ipSrc); + vxlanBuilder.setDst(ipDst); + final TunnelParameters tunnelParameters = config.getTunnelParameters(); + if (tunnelParameters instanceof org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vbridge.topology.rev160129.network.topology.topology.tunnel.parameters.Vxlan) { + org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vbridge.topology.rev160129.network.topology.topology.tunnel.parameters.Vxlan vxlan = + (org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vbridge.topology.rev160129.network.topology.topology.tunnel.parameters.Vxlan) tunnelParameters; + //TODO: handle NPE + vxlanBuilder.setVni(vxlan.getVxlan().getVni()); + } + vxlanBuilder.setEncapVrfId(DEFAULT_ENCAP_VRF_ID); + return vxlanBuilder.build(); + } + + + public void setConfig(final TopologyVbridgeAugment config) { + this.config = config; + } +} |