2 * Copyright (c) 2015 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
9 package org.opendaylight.bgpcep.pcep.tunnel.provider;
11 import com.google.common.base.Function;
12 import com.google.common.base.Optional;
13 import com.google.common.base.Preconditions;
14 import com.google.common.util.concurrent.Futures;
15 import com.google.common.util.concurrent.ListenableFuture;
16 import java.util.List;
17 import org.opendaylight.bgpcep.pcep.topology.spi.AbstractInstructionExecutor;
18 import org.opendaylight.bgpcep.programming.topology.TopologyProgrammingUtil;
19 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
20 import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction;
21 import org.opendaylight.controller.md.sal.binding.api.ReadTransaction;
22 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
23 import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException;
24 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IpAddress;
25 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev131222.AdministrativeStatus;
26 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev131222.Arguments2;
27 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev131222.Arguments2Builder;
28 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev131222.PcepCreateP2pTunnelInput1;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev131222.lsp.object.LspBuilder;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev131005.bandwidth.object.BandwidthBuilder;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev131005.classtype.object.ClassTypeBuilder;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev131005.endpoints.AddressFamily;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev131005.endpoints.address.family.Ipv4CaseBuilder;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev131005.endpoints.address.family.Ipv6CaseBuilder;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev131005.endpoints.address.family.ipv4._case.Ipv4Builder;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev131005.endpoints.address.family.ipv6._case.Ipv6Builder;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev131005.endpoints.object.EndpointsObjBuilder;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev131005.lspa.object.LspaBuilder;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev131024.AddLspInput;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev131024.AddLspInputBuilder;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev131024.AddLspOutput;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev131024.NetworkTopologyPcepService;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev131024.OperationResult;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev131024.add.lsp.args.Arguments;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev131024.add.lsp.args.ArgumentsBuilder;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.tunnel.pcep.programming.rev131030.PcepCreateP2pTunnelInput;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.tunnel.programming.rev130930.TpReference;
48 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.Topology;
49 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Link;
50 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
51 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.NodeKey;
52 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.node.TerminationPoint;
53 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.node.TerminationPointKey;
54 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.nt.l3.unicast.igp.topology.rev131021.TerminationPoint1;
55 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.nt.l3.unicast.igp.topology.rev131021.igp.termination.point.attributes.igp.termination.point.attributes.TerminationPointType;
56 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.nt.l3.unicast.igp.topology.rev131021.igp.termination.point.attributes.igp.termination.point.attributes.termination.point.type.Ip;
57 import org.opendaylight.yangtools.yang.binding.DataObject;
58 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
59 import org.opendaylight.yangtools.yang.common.RpcResult;
61 final class CreateTunnelInstructionExecutor extends AbstractInstructionExecutor {
62 private final DataBroker dataProvider;
63 private final NetworkTopologyPcepService topologyService;
64 private final PcepCreateP2pTunnelInput p2pTunnelInput;
66 CreateTunnelInstructionExecutor(final PcepCreateP2pTunnelInput p2pTunnelInput, final DataBroker dataProvider,
67 final NetworkTopologyPcepService topologyService) {
68 super(p2pTunnelInput);
69 this.p2pTunnelInput = p2pTunnelInput;
70 this.dataProvider = dataProvider;
71 this.topologyService = topologyService;
74 private static final class TpReader {
75 private final ReadTransaction t;
76 private final InstanceIdentifier<Node> nii;
77 private final InstanceIdentifier<TerminationPoint> tii;
79 TpReader(final ReadTransaction t, final InstanceIdentifier<Topology> topo, final TpReference ref) {
80 this.t = Preconditions.checkNotNull(t);
82 this.nii = topo.child(Node.class, new NodeKey(ref.getNode()));
83 this.tii = this.nii.child(TerminationPoint.class, new TerminationPointKey(ref.getTp()));
86 private DataObject read(final InstanceIdentifier<?> id) {
88 return this.t.read(LogicalDatastoreType.OPERATIONAL, id).checkedGet().get();
89 } catch (ReadFailedException | IllegalStateException e) {
90 throw new IllegalStateException("Failed to read data.", e);
94 private Node getNode() {
95 return (Node) read(this.nii);
98 private TerminationPoint getTp() {
99 return (TerminationPoint) read(this.tii);
104 protected ListenableFuture<OperationResult> invokeOperation() {
105 try (final ReadOnlyTransaction transaction = this.dataProvider.newReadOnlyTransaction()) {
106 AddLspInput addLspInput = createAddLspInput(transaction);
108 return Futures.transform(
109 (ListenableFuture<RpcResult<AddLspOutput>>) this.topologyService.addLsp(addLspInput),
110 new Function<RpcResult<AddLspOutput>, OperationResult>() {
112 public OperationResult apply(final RpcResult<AddLspOutput> input) {
113 return input.getResult();
119 private AddLspInput createAddLspInput(final ReadOnlyTransaction transaction) {
120 final InstanceIdentifier<Topology> tii = TopologyProgrammingUtil.topologyForInput(this.p2pTunnelInput);
121 final TpReader dr = new TpReader(transaction, tii, this.p2pTunnelInput.getDestination());
122 final TerminationPoint dp = Preconditions.checkNotNull(dr.getTp());
124 final TpReader sr = new TpReader(transaction, tii, this.p2pTunnelInput.getSource());
125 final TerminationPoint sp = Preconditions.checkNotNull(sr.getTp());
127 final Node sn = Preconditions.checkNotNull(sr.getNode());
128 final AddLspInputBuilder ab = new AddLspInputBuilder();
129 ab.setNode(Preconditions.checkNotNull(TunelProgrammingUtil.supportingNode(sn)));
130 ab.setName(this.p2pTunnelInput.getSymbolicPathName());
132 checkLinkIsnotExistent(tii, ab, transaction);
134 ab.setArguments(buildArguments(sp, dp));
138 private static void checkLinkIsnotExistent(final InstanceIdentifier<Topology> tii, final AddLspInputBuilder addLspInput,
139 final ReadOnlyTransaction t) {
140 final InstanceIdentifier<Link> lii = NodeChangedListener.linkIdentifier(tii, addLspInput.getNode(), addLspInput.getName());
142 Preconditions.checkState(!t.read(LogicalDatastoreType.OPERATIONAL, lii).checkedGet().isPresent());
143 } catch (final ReadFailedException e) {
144 throw new IllegalStateException("Failed to ensure link existence.", e);
148 private Arguments buildArguments(final TerminationPoint sp, final TerminationPoint dp) {
149 final ArgumentsBuilder args = new ArgumentsBuilder();
150 if (this.p2pTunnelInput.getBandwidth() != null) {
151 args.setBandwidth(new BandwidthBuilder().setBandwidth(this.p2pTunnelInput.getBandwidth()).build());
153 if (this.p2pTunnelInput.getClassType() != null) {
154 args.setClassType(new ClassTypeBuilder().setClassType(this.p2pTunnelInput.getClassType()).build());
156 args.setEndpointsObj(new EndpointsObjBuilder().setAddressFamily(buildAddressFamily(sp, dp)).build());
157 args.setEro(TunelProgrammingUtil.buildEro(this.p2pTunnelInput.getExplicitHops()));
158 args.setLspa(new LspaBuilder(this.p2pTunnelInput).build());
160 final AdministrativeStatus adminStatus = this.p2pTunnelInput.getAugmentation(PcepCreateP2pTunnelInput1.class).getAdministrativeStatus();
161 if (adminStatus != null) {
162 args.addAugmentation(Arguments2.class, new Arguments2Builder().setLsp(new LspBuilder().setAdministrative((adminStatus == AdministrativeStatus.Active) ? true : false).build()).build());
167 private static AddressFamily buildAddressFamily(final TerminationPoint sp, final TerminationPoint dp) {
168 // We need the IGP augmentation -- it has IP addresses
169 final TerminationPoint1 sp1 = Preconditions.checkNotNull(sp.getAugmentation(TerminationPoint1.class));
170 final TerminationPoint1 dp1 = Preconditions.checkNotNull(dp.getAugmentation(TerminationPoint1.class));
173 final TerminationPointType spt = sp1.getIgpTerminationPointAttributes().getTerminationPointType();
174 final TerminationPointType dpt = dp1.getIgpTerminationPointAttributes().getTerminationPointType();
176 // The types have to match
177 Preconditions.checkArgument(spt.getImplementedInterface().equals(dpt.getImplementedInterface()));
179 // And they have to actually be Ip
180 final Ip sips = (Ip) spt;
181 final Ip dips = (Ip) dpt;
184 * Now a bit of magic. We need to find 'like' addresses, e.g. both
185 * IPv4 or both IPv6. We are in IPv6-enabled world now, so let's
188 Optional<AddressFamily> ret = findIpv6(sips.getIpAddress(), dips.getIpAddress());
189 if (!ret.isPresent()) {
190 ret = findIpv4(sips.getIpAddress(), dips.getIpAddress());
193 // We need to have a ret now
194 Preconditions.checkArgument(ret != null, "Failed to find like Endpoint addresses");
199 private static Optional<AddressFamily> findIpv4(final List<IpAddress> srcs, final List<IpAddress> dsts) {
200 for (final IpAddress sc : srcs) {
201 if (sc.getIpv4Address() != null) {
202 for (final IpAddress dc : dsts) {
203 if (dc.getIpv4Address() != null) {
204 return Optional.<AddressFamily>of(new Ipv4CaseBuilder().setIpv4(new Ipv4Builder().setSourceIpv4Address(sc.getIpv4Address()).
205 setDestinationIpv4Address(dc.getIpv4Address()).build()).build());
214 private static Optional<AddressFamily> findIpv6(final List<IpAddress> srcs, final List<IpAddress> dsts) {
215 for (final IpAddress sc : srcs) {
216 if (sc.getIpv6Address() != null) {
217 for (final IpAddress dc : dsts) {
218 if (dc.getIpv6Address() != null) {
219 return Optional.<AddressFamily>of(new Ipv6CaseBuilder().setIpv6(new Ipv6Builder().setSourceIpv6Address(sc.getIpv6Address()).
220 setDestinationIpv6Address(dc.getIpv6Address()).build()).build());
226 return Optional.absent();