2 * Copyright (c) 2016 Cisco Systems, Inc. and others. All rights reserved.
4 * This program and the accompanying materials are made available under the
5 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6 * and is available at http://www.eclipse.org/legal/epl-v10.html
8 package io.fd.honeycomb.vbd.impl;
10 import com.google.common.base.Optional;
11 import com.google.common.util.concurrent.CheckedFuture;
12 import com.google.common.util.concurrent.FutureCallback;
13 import com.google.common.util.concurrent.Futures;
14 import com.google.common.util.concurrent.ListenableFuture;
15 import com.google.common.util.concurrent.SettableFuture;
16 import java.util.ArrayList;
17 import java.util.List;
18 import javax.annotation.Nullable;
19 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
20 import org.opendaylight.controller.md.sal.binding.api.MountPointService;
21 import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction;
22 import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
23 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
24 import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException;
25 import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
26 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv4AddressNoZone;
27 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.Interfaces;
28 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface;
29 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.InterfaceBuilder;
30 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.InterfaceKey;
31 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.Interface1;
32 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces._interface.Ipv4;
33 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces._interface.ipv4.Address;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.external.reference.rev160129.ExternalReference;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.Vpp;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VppInterfaceAugmentation;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VppInterfaceAugmentationBuilder;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VxlanTunnel;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces._interface.L2;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces._interface.L2Builder;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces._interface.Vxlan;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces._interface.VxlanBuilder;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces._interface.l2.interconnection.BridgeBasedBuilder;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.BridgeDomains;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.bridge.domains.BridgeDomainBuilder;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.bridge.domains.BridgeDomainKey;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vbridge.topology.rev160129.TerminationPointVbridgeAugment;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vbridge.topology.rev160129.TopologyVbridgeAugment;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vbridge.topology.rev160129.network.topology.topology.TunnelParameters;
50 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vbridge.topology.rev160129.network.topology.topology.node.termination.point.InterfaceType;
51 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vbridge.topology.rev160129.network.topology.topology.node.termination.point._interface.type.UserInterface;
52 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
53 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.NodeKey;
54 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
55 import org.opendaylight.yangtools.yang.binding.KeyedInstanceIdentifier;
56 import org.slf4j.Logger;
57 import org.slf4j.LoggerFactory;
60 * Class which is used for manipulation with VPP
62 public class VppModifier {
63 private static final Long DEFAULT_ENCAP_VRF_ID = 0L;
65 private static final Logger LOG = LoggerFactory.getLogger(BridgeDomain.class);
66 private final MountPointService mountService;
67 private final String bridgeDomainName;
68 private TopologyVbridgeAugment config;
69 private final InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.bridge.domains.BridgeDomain> iiBridgeDomainOnVPP;
72 public VppModifier(final MountPointService mountService, final String bridgeDomainName) {
73 this.mountService = mountService;
74 this.bridgeDomainName = bridgeDomainName;
75 this.iiBridgeDomainOnVPP = InstanceIdentifier.create(Vpp.class)
76 .child(BridgeDomains.class)
77 .child(org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.bridge.domains.BridgeDomain.class, new BridgeDomainKey(bridgeDomainName));
80 * Tryies to read ipv4 addresses from all specified {@code iiToVpps } vpps.
82 * @param iiToVpps collection of instance identifiers which points to concrete mount points.
83 * @return future which contains list of ip addreases in the same order as was specified in {@code iiToVpps}
85 ListenableFuture<List<Optional<Ipv4AddressNoZone>>> readIpAddressesFromVpps(final KeyedInstanceIdentifier<Node, NodeKey>... iiToVpps) {
86 final List<ListenableFuture<Optional<Ipv4AddressNoZone>>> ipv4Futures = new ArrayList<>();
87 for (final KeyedInstanceIdentifier<Node, NodeKey> iiToVpp : iiToVpps) {
88 ipv4Futures.add(readIpAddressFromVpp(iiToVpp));
90 return Futures.successfulAsList(ipv4Futures);
94 * Passes through interfaces at mount point specified via {@code iiToVpp}.
96 * When first ipv4 address is found then it is returned.
98 * @param iiToVpp instance idenfifier which point to mounted vpp
99 * @return if set ipv4 address is found at mounted vpp then it is returned as future. Otherwise absent value is returned
100 * in future or exception which has been thrown
102 private ListenableFuture<Optional<Ipv4AddressNoZone>> readIpAddressFromVpp(final KeyedInstanceIdentifier<Node, NodeKey> iiToVpp) {
103 final SettableFuture<Optional<Ipv4AddressNoZone>> resultFuture = SettableFuture.create();
105 final DataBroker vppDataBroker = VbdUtil.resolveDataBrokerForMountPoint(iiToVpp, mountService);
106 if (vppDataBroker != null) {
107 final ReadOnlyTransaction rTx = vppDataBroker.newReadOnlyTransaction();
108 final CheckedFuture<Optional<Interfaces>, ReadFailedException> interfaceStateFuture
109 = rTx.read(LogicalDatastoreType.CONFIGURATION, InstanceIdentifier.create(Interfaces.class));
111 Futures.addCallback(interfaceStateFuture, new FutureCallback<Optional<Interfaces>>() {
113 public void onSuccess(final Optional<Interfaces> optInterfaces) {
114 if (optInterfaces.isPresent()) {
115 for (org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface intf : optInterfaces.get().getInterface()) {
116 final Interface1 interface1 = intf.getAugmentation(Interface1.class);
117 if (interface1 != null) {
118 final Ipv4 ipv4 = interface1.getIpv4();
120 final List<Address> addresses = ipv4.getAddress();
121 if (!addresses.isEmpty()) {
122 final Ipv4AddressNoZone ip = addresses.iterator().next().getIp();
124 resultFuture.set(Optional.of(ip));
132 LOG.debug("There is no inferface with ipv4 address set at VPP {}.", iiToVpp);
133 resultFuture.set(Optional.<Ipv4AddressNoZone>absent());
138 public void onFailure(Throwable t) {
139 resultFuture.setException(t);
143 LOG.debug("Data broker for vpp {} is missing.", iiToVpp);
144 resultFuture.set(Optional.<Ipv4AddressNoZone>absent());
149 void createVirtualInterfaceOnVpp(final Ipv4AddressNoZone ipSrc, final Ipv4AddressNoZone ipDst, final KeyedInstanceIdentifier<Node, NodeKey> iiToVpp,
150 final Integer vxlanTunnelId) {
151 final Vxlan vxlanData = prepareVxlan(ipSrc, ipDst);
152 final Interface intfData = prepareVirtualInterfaceData(vxlanData, vxlanTunnelId);
154 final DataBroker vppDataBroker = VbdUtil.resolveDataBrokerForMountPoint(iiToVpp, mountService);
155 if (vppDataBroker != null) {
156 final WriteTransaction wTx = vppDataBroker.newWriteOnlyTransaction();
157 final KeyedInstanceIdentifier<Interface, InterfaceKey> iiToInterface
158 = InstanceIdentifier.create(Interfaces.class).child(Interface.class, new InterfaceKey(VbdUtil.provideVxlanId(vxlanTunnelId)));
159 wTx.put(LogicalDatastoreType.CONFIGURATION, iiToInterface, intfData);
160 final CheckedFuture<Void, TransactionCommitFailedException> submitFuture = wTx.submit();
161 Futures.addCallback(submitFuture, new FutureCallback<Void>() {
163 public void onSuccess(@Nullable Void result) {
164 LOG.debug("Writing super virtual interface to {} finished successfully.",iiToVpp.getKey().getNodeId());
168 public void onFailure(Throwable t) {
169 LOG.debug("Writing super virtual interface to {} failed.", iiToVpp.getKey().getNodeId());
173 LOG.debug("Writing virtual interface {} to VPP {} wasn't successfull because missing data broker.", VbdUtil.provideVxlanId(vxlanTunnelId), iiToVpp);
177 private Interface prepareVirtualInterfaceData(final Vxlan vxlan, Integer vxlanTunnelId) {
178 final InterfaceBuilder interfaceBuilder = new InterfaceBuilder();
179 //TODO implement tunnel counter
180 interfaceBuilder.setName(VbdUtil.provideVxlanId(vxlanTunnelId));
181 interfaceBuilder.setType(VxlanTunnel.class);
182 VppInterfaceAugmentationBuilder vppInterfaceAugmentationBuilder = new VppInterfaceAugmentationBuilder();
183 vppInterfaceAugmentationBuilder.setVxlan(vxlan);
184 interfaceBuilder.addAugmentation(VppInterfaceAugmentation.class, vppInterfaceAugmentationBuilder.build());
185 return interfaceBuilder.build();
188 private Vxlan prepareVxlan(final Ipv4AddressNoZone ipSrc, final Ipv4AddressNoZone ipDst) {
189 final VxlanBuilder vxlanBuilder = new VxlanBuilder();
190 vxlanBuilder.setSrc(ipSrc);
191 vxlanBuilder.setDst(ipDst);
192 final TunnelParameters tunnelParameters = config.getTunnelParameters();
193 if (tunnelParameters instanceof org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vbridge.topology.rev160129.network.topology.topology.tunnel.parameters.Vxlan) {
194 org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vbridge.topology.rev160129.network.topology.topology.tunnel.parameters.Vxlan vxlan =
195 (org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vbridge.topology.rev160129.network.topology.topology.tunnel.parameters.Vxlan) tunnelParameters;
197 vxlanBuilder.setVni(vxlan.getVxlan().getVni());
199 vxlanBuilder.setEncapVrfId(DEFAULT_ENCAP_VRF_ID);
200 return vxlanBuilder.build();
203 void addInterfaceToBridgeDomainOnVpp(final DataBroker vppDataBroker, final TerminationPointVbridgeAugment termPointVbridgeAug) {
204 final InterfaceType interfaceType = termPointVbridgeAug.getInterfaceType();
205 if (interfaceType instanceof UserInterface) {
206 //REMARK: according contract in YANG model this should be URI to data on mount point (accroding to RESTCONF)
207 //It was much more easier to just await concrete interface name, thus isn't necessary parse it (splitting on '/')
208 final ExternalReference userInterface = ((UserInterface) interfaceType).getUserInterface();
209 final KeyedInstanceIdentifier<Interface, InterfaceKey> iiToVpp =
210 InstanceIdentifier.create(Interfaces.class)
211 .child(Interface.class, new InterfaceKey(userInterface.getValue()));
212 InstanceIdentifier<L2> iiToV3poL2 = iiToVpp.augmentation(VppInterfaceAugmentation.class).child(L2.class);
213 LOG.debug("Writing L2 data to configuration DS to concrete interface.");
214 final WriteTransaction wTx = vppDataBroker.newWriteOnlyTransaction();
215 wTx.put(LogicalDatastoreType.CONFIGURATION, iiToV3poL2, prepareL2Data(), true);
220 ListenableFuture<Void> addVppToBridgeDomain(final KeyedInstanceIdentifier<Node, NodeKey> iiToVpp, final Node node) {
221 final DataBroker vppDataBroker = VbdUtil.resolveDataBrokerForMountPoint(iiToVpp, mountService);
222 if (vppDataBroker != null) {
223 final WriteTransaction wTx = vppDataBroker.newWriteOnlyTransaction();
224 wTx.put(LogicalDatastoreType.CONFIGURATION, iiBridgeDomainOnVPP, prepareNewBridgeDomainData(), true);
227 return Futures.immediateFailedFuture(new IllegalStateException("Data broker for vpp is missing"));
230 private org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.bridge.domains.BridgeDomain
231 prepareNewBridgeDomainData() {
232 final BridgeDomainBuilder bridgeDomainBuilder = new BridgeDomainBuilder(config);
233 bridgeDomainBuilder.setName(bridgeDomainName);
234 return bridgeDomainBuilder.build();
239 private L2 prepareL2Data() {
240 final L2Builder l2Builder = new L2Builder();
241 final BridgeBasedBuilder bridgeBasedBuilder = new BridgeBasedBuilder();
242 bridgeBasedBuilder.setSplitHorizonGroup((short) 0);
243 bridgeBasedBuilder.setBridgedVirtualInterface(false);
244 bridgeBasedBuilder.setBridgeDomain(bridgeDomainName);
245 l2Builder.setInterconnection(bridgeBasedBuilder.build());
246 return l2Builder.build();
249 public void setConfig(final TopologyVbridgeAugment config) {
250 this.config = config;