From 809e3e17a7582e56404c95e645914dd341fa379e Mon Sep 17 00:00:00 2001 From: Jozef Gloncak Date: Wed, 3 Feb 2016 11:18:51 +0100 Subject: Adding termination point to VBD on VPP. Creation request from UI for creating new termination point cause that interface on VPP is added to virtual bridge domain. Change-Id: I73910e31250c81e9e8baac40072926bdfc71ff22 Signed-off-by: Jozef Gloncak --- vbd/api/src/main/yang/vbridge-topology.yang | 1 + .../io/fd/honeycomb/vbd/impl/BridgeDomain.java | 111 +++++++++++++++++---- vbd/impl/vbridge-workflow.txt | 10 +- 3 files changed, 94 insertions(+), 28 deletions(-) (limited to 'vbd') diff --git a/vbd/api/src/main/yang/vbridge-topology.yang b/vbd/api/src/main/yang/vbridge-topology.yang index 901907387..e0ff290f4 100644 --- a/vbd/api/src/main/yang/vbridge-topology.yang +++ b/vbd/api/src/main/yang/vbridge-topology.yang @@ -118,6 +118,7 @@ module vbridge-topology { } augment "/nt:network-topology/nt:topology/nt:node/nt:termination-point" { + ext:augment-identifier "termination-point-vbridge-augment"; when "../bridge-member"; choice interface-type { 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 6105cb26d..82558684f 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 @@ -10,6 +10,8 @@ package io.fd.honeycomb.vbd.impl; import com.google.common.base.Optional; import com.google.common.base.Preconditions; +import com.google.common.collect.ArrayListMultimap; +import com.google.common.collect.Multimap; import com.google.common.util.concurrent.CheckedFuture; import com.google.common.util.concurrent.FutureCallback; import com.google.common.util.concurrent.Futures; @@ -27,15 +29,25 @@ 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.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.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.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.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; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.bridge.domains.BridgeDomainKey; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vbridge.topology.rev160129.NodeVbridgeAugment; +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.TopologyVbridgeAugment; 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; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vbridge.topology.rev160129.network.topology.topology.node.termination.point._interface.type.UserInterface; 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; @@ -43,6 +55,7 @@ import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.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.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.node.TerminationPoint; import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.node.attributes.SupportingNode; import org.opendaylight.yangtools.concepts.ListenerRegistration; import org.opendaylight.yangtools.yang.binding.DataObject; @@ -68,6 +81,7 @@ final class BridgeDomain implements DataTreeChangeListener { private final InstanceIdentifier iiBridgeDomainOnVPP; private final String iiBridgeDomainOnVPPRest; private final DataBroker dataBroker; + private Multimap> nodesToVpps = ArrayListMultimap.create(); private BridgeDomain(final DataBroker dataBroker, final MountPointService mountService, final KeyedInstanceIdentifier topology, final BindingTransactionChain chain) { @@ -148,7 +162,7 @@ final class BridgeDomain implements DataTreeChangeListener { LOG.debug("Topology {} modified child {}", topology, child); if (Node.class.isAssignableFrom(child.getDataType())) { - modifyNode((DataObjectModification) child, newConfig.getDataAfter()); + modifyNode((DataObjectModification) child); } } @@ -174,27 +188,84 @@ final class BridgeDomain implements DataTreeChangeListener { } } - private void modifyNode(final DataObjectModification child, final TopologyVbridgeAugment topologyVbridgeAugment) { - switch (child.getModificationType()) { + private void modifyNode(final DataObjectModification nodeMod) { + switch (nodeMod.getModificationType()) { case DELETE: - LOG.debug("Topology {} node {} deleted", topology, child.getIdentifier()); + LOG.debug("Topology {} node {} deleted", topology, nodeMod.getIdentifier()); // FIXME: do something break; case SUBTREE_MODIFIED: - LOG.debug("Topology {} node {} modified", topology, child.getIdentifier()); - // FIXME: do something + LOG.debug("Topology {} node {} modified", topology, nodeMod.getIdentifier()); + for (DataObjectModification nodeChild : nodeMod.getModifiedChildren()) { + if (TerminationPoint.class.isAssignableFrom(nodeChild.getDataType())) { + modifyTerminationPoint((DataObjectModification) nodeChild,nodeMod.getDataAfter().getNodeId()); + } + } break; case WRITE: - LOG.debug("Topology {} node {} created", topology, child.getIdentifier()); - createNode(child.getDataAfter(), topologyVbridgeAugment); + LOG.debug("Topology {} node {} created", topology, nodeMod.getIdentifier()); + createNode(nodeMod.getDataAfter()); break; default: - LOG.warn("Unhandled node modification {} in topology {}", child, topology); + LOG.warn("Unhandled node modification {} in topology {}", nodeMod, topology); break; } } - private void createNode(final Node node, final TopologyVbridgeAugment topologyVbridgeAugment) { + private void modifyTerminationPoint(final DataObjectModification nodeChild, final NodeId nodeId) { + final TerminationPoint terminationPoint = nodeChild.getDataAfter(); + final TerminationPointVbridgeAugment termPointVbridgeAug = terminationPoint.getAugmentation(TerminationPointVbridgeAugment.class); + if (termPointVbridgeAug != null) { + final Collection> instanceIdentifiersVPP = nodesToVpps.get(nodeId); + //TODO: probably iterate via all instance identifiers. + if (!instanceIdentifiersVPP.isEmpty()) { + final DataBroker dataBroker = resolveDataBrokerForMountPoint(instanceIdentifiersVPP.iterator().next()); + addInterfaceToBridgeDomainOnVpp(dataBroker, termPointVbridgeAug); + } + } + } + + private void addInterfaceToBridgeDomainOnVpp(final DataBroker vppDataBroker, final TerminationPointVbridgeAugment termPointVbridgeAug) { + final InterfaceType interfaceType = termPointVbridgeAug.getInterfaceType(); + if (interfaceType instanceof UserInterface) { + //REMARK: according contract in YANG model this should be URI to data on mount point (accroding to RESTCONF) + //It was much more easier to just await concrete interface name, thus isn't necessary parse it (splitting on '/') + final ExternalReference userInterface = ((UserInterface) interfaceType).getUserInterface(); + final KeyedInstanceIdentifier iiToVpp = + InstanceIdentifier.create(Interfaces.class) + .child(Interface.class, new InterfaceKey(userInterface.getValue())); + InstanceIdentifier iiToV3poL2 = iiToVpp.augmentation(VppInterfaceAugmentation.class).child(L2.class); + LOG.debug("Writing L2 data to configuration DS to concrete interface."); + final WriteTransaction wTx = vppDataBroker.newWriteOnlyTransaction(); + wTx.put(LogicalDatastoreType.CONFIGURATION, iiToV3poL2, prepareL2Data()); + wTx.submit(); + } + } + + private L2 prepareL2Data() { + final L2Builder l2Builder = new L2Builder(); + final BridgeBasedBuilder bridgeBasedBuilder = new BridgeBasedBuilder(); + bridgeBasedBuilder.setSplitHorizonGroup((short) 0); + bridgeBasedBuilder.setBridgedVirtualInterface(false); + bridgeBasedBuilder.setBridgeDomain(bridgeDomainName); + l2Builder.setInterconnection(bridgeBasedBuilder.build()); + return l2Builder.build(); + } + + + private DataBroker resolveDataBrokerForMountPoint(final InstanceIdentifier iiToMountPoint) { + final Optional vppMountPointOpt = mountService.getMountPoint(iiToMountPoint); + if (vppMountPointOpt.isPresent()) { + final MountPoint vppMountPoint = vppMountPointOpt.get(); + final Optional dataBrokerOpt = vppMountPoint.getService(DataBroker.class); + if (dataBrokerOpt.isPresent()) { + return dataBrokerOpt.get(); + } + } + return null; + } + + private void createNode(final Node node) { for (SupportingNode supportingNode : node.getSupportingNode()) { final NodeId nodeMount = supportingNode.getNodeRef(); final TopologyId topologyMount = supportingNode.getTopologyRef(); @@ -203,20 +274,16 @@ final class BridgeDomain implements DataTreeChangeListener { .create(NetworkTopology.class) .child(Topology.class, new TopologyKey(topologyMount)) .child(Node.class, new NodeKey(nodeMount)); - final Optional vppMountOption = mountService.getMountPoint(iiToMount); - if (vppMountOption.isPresent()) { - final MountPoint vppMount = vppMountOption.get(); - addVppToBridgeDomain(topologyVbridgeAugment, vppMount, node); - } + nodesToVpps.put(node.getNodeId(), iiToMount); + final DataBroker dataBrokerOfMount = resolveDataBrokerForMountPoint(iiToMount); + addVppToBridgeDomain(dataBrokerOfMount, node); } } - private void addVppToBridgeDomain(final TopologyVbridgeAugment topologyVbridgeAugment, final MountPoint vppMount, final Node node) { - final Optional dataBrokerOpt = vppMount.getService(DataBroker.class); - if (dataBrokerOpt.isPresent()) { - final DataBroker vppDataBroker = dataBrokerOpt.get(); + private void addVppToBridgeDomain(final DataBroker vppDataBroker, final Node node) { + if (vppDataBroker != null) { final WriteTransaction wTx = vppDataBroker.newWriteOnlyTransaction(); - wTx.put(LogicalDatastoreType.OPERATIONAL, iiBridgeDomainOnVPP, prepareNewBridgeDomainData(topologyVbridgeAugment)); + wTx.put(LogicalDatastoreType.CONFIGURATION, iiBridgeDomainOnVPP, prepareNewBridgeDomainData()); final CheckedFuture addVppToBridgeDomainFuture = wTx.submit(); addSupportingBridgeDomain(addVppToBridgeDomainFuture, node); } @@ -244,8 +311,8 @@ final class BridgeDomain implements DataTreeChangeListener { } private org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.bridge.domains.BridgeDomain - prepareNewBridgeDomainData(TopologyVbridgeAugment topologyVbridgeAugment) { - final BridgeDomainBuilder bridgeDomainBuilder = new BridgeDomainBuilder(topologyVbridgeAugment); + prepareNewBridgeDomainData() { + final BridgeDomainBuilder bridgeDomainBuilder = new BridgeDomainBuilder(config); bridgeDomainBuilder.setName(topology.getKey().getTopologyId().getValue()); return bridgeDomainBuilder.build(); } diff --git a/vbd/impl/vbridge-workflow.txt b/vbd/impl/vbridge-workflow.txt index 86ba544f4..9f93e6fd4 100644 --- a/vbd/impl/vbridge-workflow.txt +++ b/vbd/impl/vbridge-workflow.txt @@ -32,7 +32,7 @@ Prerequisite: configured netconf-node-topology - bridge-member container - supporting-node pointing to the VPP node in the netconf-node-topology - + B) The Controller App receives a DataTreeChangeNotification about the node being added, and: @@ -46,7 +46,7 @@ Prerequisite: configured netconf-node-topology datastore. The leaf contains a RESTCONF-encoded instance identifier of the bridge domain created in the VPP, relative to that VPP's mount point. - + 3) Assigning a physical VPP interface into a Virtual Bridge Domain Prerequisite: The VPP itself has been added to the Virtual Bridge Domain @@ -54,9 +54,7 @@ Prerequisite: configured netconf-node-topology A) The UI creates a 'termination-point' inside the 'node' added in 2), with: - - user-interface, containing RESTCONF-encoded instance identifier - of the VPP interface, relative to that VPP's mount point in config - data store. + - interface name. B) The Controller App receives a notification of this being done and: - looks if the VPP is connected, if it is, the app will: @@ -64,7 +62,7 @@ Prerequisite: configured netconf-node-topology Inverse operations are achieved by the UI deleting the corresponding nodes in the Controller's configuration data store. - + Virtual Bridge Domain tunnel management --------------------------------------- -- cgit 1.2.3-korg