2 * Copyright (c) 2014 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 org.opendaylight.bgpcep.pcep.tunnel.provider;
10 import static org.junit.Assert.assertEquals;
11 import static org.junit.Assert.assertNotNull;
12 import static org.mockito.ArgumentMatchers.any;
13 import static org.mockito.Mockito.doAnswer;
14 import static org.mockito.Mockito.doNothing;
15 import static org.mockito.Mockito.doReturn;
17 import com.google.common.util.concurrent.ListenableFuture;
18 import java.util.List;
20 import java.util.concurrent.ExecutionException;
21 import java.util.concurrent.Executor;
22 import org.junit.Before;
23 import org.junit.Test;
24 import org.junit.runner.RunWith;
25 import org.mockito.ArgumentMatchers;
26 import org.mockito.Mock;
27 import org.mockito.Mockito;
28 import org.mockito.junit.MockitoJUnitRunner;
29 import org.opendaylight.bgpcep.programming.spi.Instruction;
30 import org.opendaylight.bgpcep.programming.spi.InstructionScheduler;
31 import org.opendaylight.bgpcep.programming.spi.SchedulerException;
32 import org.opendaylight.mdsal.binding.api.RpcProviderService;
33 import org.opendaylight.mdsal.binding.api.RpcService;
34 import org.opendaylight.mdsal.binding.api.WriteTransaction;
35 import org.opendaylight.mdsal.binding.dom.adapter.test.AbstractConcurrentDataBrokerTest;
36 import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
37 import org.opendaylight.mdsal.singleton.api.ClusterSingletonServiceProvider;
38 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress;
39 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpPrefix;
40 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv4Address;
41 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv4Prefix;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.network.concepts.rev131125.Bandwidth;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.network.topology.rev140113.NetworkTopologyRef;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev200720.AdministrativeStatus;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev200720.PcepCreateP2pTunnelInput1Builder;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev200720.PcepUpdateTunnelInput1Builder;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev181109.ClassType;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev181109.endpoints.address.family.Ipv4Case;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev181109.endpoints.address.family.ipv4._case.Ipv4;
50 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev181109.explicit.route.object.ero.Subobject;
51 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.programming.rev150720.InstructionStatus;
52 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.programming.rev150720.SubmitInstructionInput;
53 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.rsvp.rev150820.basic.explicit.route.subobjects.subobject.type.IpPrefixCase;
54 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.rsvp.rev150820.basic.explicit.route.subobjects.subobject.type.IpPrefixCaseBuilder;
55 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.rsvp.rev150820.basic.explicit.route.subobjects.subobject.type.ip.prefix._case.IpPrefixBuilder;
56 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev220730.AddLsp;
57 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev220730.AddLspInput;
58 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev220730.AddLspOutput;
59 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev220730.RemoveLsp;
60 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev220730.RemoveLspInput;
61 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev220730.RemoveLspOutput;
62 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev220730.UpdateLsp;
63 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev220730.UpdateLspInput;
64 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev220730.UpdateLspOutput;
65 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev220730.add.lsp.args.Arguments;
66 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.tunnel.p2p.rev130819.tunnel.p2p.path.cfg.attributes.ExplicitHops;
67 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.tunnel.p2p.rev130819.tunnel.p2p.path.cfg.attributes.ExplicitHopsBuilder;
68 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.tunnel.pcep.programming.rev181109.PcepCreateP2pTunnelInputBuilder;
69 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.tunnel.pcep.programming.rev181109.PcepDestroyTunnelInputBuilder;
70 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.tunnel.pcep.programming.rev181109.PcepUpdateTunnelInputBuilder;
71 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.tunnel.pcep.rev181109.ExplicitHops1Builder;
72 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.tunnel.pcep.rev181109.Link1Builder;
73 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.tunnel.pcep.rev181109.SupportingNode1Builder;
74 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.tunnel.pcep.rev181109.tunnel.pcep.supporting.node.attributes.PathComputationClientBuilder;
75 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.tunnel.programming.rev130930.create.p2p.tunnel.input.DestinationBuilder;
76 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.tunnel.programming.rev130930.create.p2p.tunnel.input.SourceBuilder;
77 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.LinkId;
78 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NetworkTopology;
79 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;
80 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.TopologyId;
81 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.TpId;
82 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.Topology;
83 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.TopologyBuilder;
84 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.TopologyKey;
85 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Link;
86 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.LinkBuilder;
87 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.LinkKey;
88 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
89 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.NodeBuilder;
90 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.node.TerminationPointBuilder;
91 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.node.attributes.SupportingNodeBuilder;
92 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.nt.l3.unicast.igp.topology.rev131021.TerminationPoint1Builder;
93 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.nt.l3.unicast.igp.topology.rev131021.igp.termination.point.attributes.IgpTerminationPointAttributesBuilder;
94 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.IpBuilder;
95 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
96 import org.opendaylight.yangtools.yang.binding.util.BindingMap;
97 import org.opendaylight.yangtools.yang.common.RpcResult;
98 import org.opendaylight.yangtools.yang.common.Uint32;
99 import org.opendaylight.yangtools.yang.common.Uint8;
100 import org.osgi.framework.BundleContext;
102 @RunWith(MockitoJUnitRunner.StrictStubs.class)
103 public class TunnelProgrammingTest extends AbstractConcurrentDataBrokerTest {
105 private static final TopologyId TOPOLOGY_ID = new TopologyId("tunnel-topo");
106 private static final InstanceIdentifier<Topology> TOPO_IID = InstanceIdentifier.builder(NetworkTopology.class)
107 .child(Topology.class, new TopologyKey(TOPOLOGY_ID)).build();
109 private static final String NODE1_IPV4 = "127.0.0.1";
110 private static final NodeId NODE1_ID = new NodeId("pcc://" + NODE1_IPV4);
111 private static final TpId TP1_ID = new TpId(NODE1_IPV4);
113 private static final String NODE2_IPV4 = "127.0.0.10";
114 private static final NodeId NODE2_ID = new NodeId("pcc://" + NODE2_IPV4);
115 private static final TpId TP2_ID = new TpId(NODE2_IPV4);
117 private static final LinkId LINK1_ID = new LinkId("link1");
119 private static final String IPV4_PREFIX1 = "195.20.160.40/32";
120 private static final String IPV4_PREFIX2 = "201.20.160.43/32";
123 private InstructionScheduler scheduler;
125 private ListenableFuture<Instruction> instructionFuture;
127 private Instruction instruction;
129 private ClusterSingletonServiceProvider cssp;
131 private RpcProviderService rpr;
133 private RpcService rpcs;
135 private BundleContext bundleContext;
137 private TunnelProgramming tunnelProgramming;
139 private AddLspInput addLspInput;
140 private UpdateLspInput updateLspInput;
141 private RemoveLspInput removeLspInput;
144 private ListenableFuture<RpcResult<AddLspOutput>> futureAddLspOutput;
146 private ListenableFuture<RpcResult<UpdateLspOutput>> futureUpdateLspOutput;
148 private ListenableFuture<RpcResult<RemoveLspOutput>> futureRemoveLspOutput;
150 private AddLsp addLsp;
152 private UpdateLsp updateLsp;
154 private RemoveLsp removeLsp;
156 private static Node createNode(final NodeId nodeId, final TpId tpId, final String ipv4Address) {
157 return new NodeBuilder()
159 .setTerminationPoint(BindingMap.of(new TerminationPointBuilder()
161 .addAugmentation(new TerminationPoint1Builder()
162 .setIgpTerminationPointAttributes(new IgpTerminationPointAttributesBuilder()
163 .setTerminationPointType(new IpBuilder()
164 .setIpAddress(Set.of(new IpAddress(new Ipv4Address(ipv4Address))))
169 .setSupportingNode(BindingMap.of(new SupportingNodeBuilder()
170 .setTopologyRef(new TopologyId("dummy"))
172 .addAugmentation(new SupportingNode1Builder()
173 .setPathComputationClient(new PathComputationClientBuilder().setControlling(true).build())
179 private static ExplicitHops createExplicitHop(final String ipv4Prefix, final Uint32 order) {
180 return new ExplicitHopsBuilder()
182 .addAugmentation(new ExplicitHops1Builder()
183 .setSubobjectType(new IpPrefixCaseBuilder().setIpPrefix(new IpPrefixBuilder()
184 .setIpPrefix(new IpPrefix(new Ipv4Prefix(ipv4Prefix))).build()).build())
190 public void setUp() throws SchedulerException, InterruptedException, ExecutionException {
191 doReturn(true).when(instruction).checkedExecutionStart();
192 doNothing().when(instruction).executionCompleted(InstructionStatus.Failed, null);
193 doAnswer(invocation -> {
194 invocation.getArgument(0, Runnable.class).run();
196 }).when(instructionFuture).addListener(ArgumentMatchers.any(Runnable.class), Mockito.any(Executor.class));
197 doReturn(false).when(futureAddLspOutput).isCancelled();
198 doAnswer(invocation -> {
199 invocation.getArgument(0, Runnable.class).run();
201 }).when(futureAddLspOutput).addListener(any(Runnable.class), any(Executor.class));
202 doReturn(false).when(futureUpdateLspOutput).isCancelled();
203 doAnswer(invocation -> {
204 invocation.getArgument(0, Runnable.class).run();
206 }).when(futureUpdateLspOutput).addListener(any(Runnable.class), any(Executor.class));
207 doReturn(false).when(futureRemoveLspOutput).isCancelled();
208 doAnswer(invocation -> {
209 invocation.getArgument(0, Runnable.class).run();
211 }).when(futureRemoveLspOutput).addListener(any(Runnable.class), any(Executor.class));
212 doAnswer(invocation -> {
213 addLspInput = invocation.getArgument(0);
214 return futureAddLspOutput;
215 }).when(addLsp).invoke(any(AddLspInput.class));
216 doAnswer(invocation -> {
217 updateLspInput = invocation.getArgument(0);
218 return futureUpdateLspOutput;
219 }).when(updateLsp).invoke(any(UpdateLspInput.class));
220 doAnswer(invocation -> {
221 removeLspInput = invocation.getArgument(0);
222 return futureRemoveLspOutput;
223 }).when(removeLsp).invoke(any(RemoveLspInput.class));
224 doReturn(instruction).when(instructionFuture).get();
225 doReturn(true).when(instructionFuture).isDone();
226 doReturn(instructionFuture).when(scheduler)
227 .scheduleInstruction(any(SubmitInstructionInput.class));
229 doReturn(addLsp).when(rpcs).getRpc(AddLsp.class);
230 doReturn(updateLsp).when(rpcs).getRpc(UpdateLsp.class);
231 doReturn(removeLsp).when(rpcs).getRpc(RemoveLsp.class);
233 createInitialTopology();
234 tunnelProgramming = new TunnelProgramming(scheduler,
235 new TunnelProviderDependencies(getDataBroker(), cssp, rpr, rpcs, bundleContext));
239 public void testTunnelProgramming() throws InterruptedException, ExecutionException {
240 final Bandwidth bwd = new Bandwidth(new byte[] { 0x00, 0x00, 0x00, (byte) 0xff });
241 final ClassType classType = new ClassType(Uint8.ONE);
242 final String tunnelName = "create-tunnel";
243 final NetworkTopologyRef topologyRef = new NetworkTopologyRef(TOPO_IID);
245 tunnelProgramming.pcepCreateP2pTunnel(new PcepCreateP2pTunnelInputBuilder()
246 .setDestination(new DestinationBuilder().setNode(NODE2_ID).setTp(TP2_ID).build())
247 .setSource(new SourceBuilder().setNode(NODE1_ID).setTp(TP1_ID).build())
248 .setNetworkTopologyRef(topologyRef)
250 .setClassType(classType)
251 .setSymbolicPathName(tunnelName)
252 .addAugmentation(new PcepCreateP2pTunnelInput1Builder()
253 .setAdministrativeStatus(AdministrativeStatus.Active)
256 //check add-lsp input
257 assertNotNull(addLspInput);
258 assertEquals(tunnelName, addLspInput.getName());
259 final Arguments agrs = addLspInput.getArguments();
261 assertEquals(bwd, agrs.getBandwidth().getBandwidth());
262 assertEquals(classType, agrs.getClassType().getClassType());
263 final Ipv4 ipv4Endpoints = ((Ipv4Case) agrs.getEndpointsObj().getAddressFamily()).getIpv4();
264 assertEquals(NODE1_IPV4, ipv4Endpoints.getSourceIpv4Address().getValue());
265 assertEquals(NODE2_IPV4, ipv4Endpoints.getDestinationIpv4Address().getValue());
266 assertEquals(NODE1_ID.getValue(), addLspInput.getNode().getValue());
270 tunnelProgramming.pcepUpdateTunnel(new PcepUpdateTunnelInputBuilder()
271 .setNetworkTopologyRef(topologyRef)
273 .setClassType(classType)
274 // We assert on explicit order
275 .setExplicitHops(BindingMap.ordered(
276 createExplicitHop(IPV4_PREFIX1, Uint32.ONE),
277 createExplicitHop(IPV4_PREFIX2, Uint32.TWO)))
279 .addAugmentation(new PcepUpdateTunnelInput1Builder()
280 .setAdministrativeStatus(AdministrativeStatus.Active)
283 //check update-lsp input
284 assertNotNull(updateLspInput);
285 assertEquals(LINK1_ID.getValue(), updateLspInput.getName());
286 final org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev220730.update.lsp
287 .args.Arguments updArgs = updateLspInput.getArguments();
288 assertEquals(2, updArgs.getEro().nonnullSubobject().size());
289 final List<Subobject> subObjects = updArgs.getEro().nonnullSubobject();
290 final IpPrefixCase prefix1 = (IpPrefixCase) subObjects.get(0).getSubobjectType();
291 final IpPrefixCase prefix2 = (IpPrefixCase) subObjects.get(1).getSubobjectType();
292 assertEquals(IPV4_PREFIX1, prefix1.getIpPrefix().getIpPrefix().getIpv4Prefix().getValue());
293 assertEquals(IPV4_PREFIX2, prefix2.getIpPrefix().getIpPrefix().getIpv4Prefix().getValue());
296 final PcepDestroyTunnelInputBuilder destroyInputBuilder = new PcepDestroyTunnelInputBuilder();
297 destroyInputBuilder.setLinkId(LINK1_ID);
298 destroyInputBuilder.setNetworkTopologyRef(topologyRef);
299 tunnelProgramming.pcepDestroyTunnel(destroyInputBuilder.build());
300 assertNotNull(removeLspInput);
301 assertEquals(LINK1_ID.getValue(), removeLspInput.getName());
302 assertEquals(NODE1_ID, removeLspInput.getNode());
305 private void createInitialTopology() throws InterruptedException, ExecutionException {
306 final WriteTransaction wTx = getDataBroker().newWriteOnlyTransaction();
307 wTx.mergeParentStructurePut(LogicalDatastoreType.OPERATIONAL, TOPO_IID, new TopologyBuilder()
308 .setTopologyId(TOPOLOGY_ID)
309 .setServerProvided(true)
310 .setTopologyId(TOPOLOGY_ID)
311 .setNode(BindingMap.of(createNode(NODE1_ID, TP1_ID, NODE1_IPV4), createNode(NODE2_ID, TP2_ID, NODE2_IPV4)))
316 private void createLink() throws InterruptedException, ExecutionException {
317 final WriteTransaction wTx = getDataBroker().newWriteOnlyTransaction();
318 wTx.mergeParentStructurePut(LogicalDatastoreType.OPERATIONAL,
319 TOPO_IID.child(Link.class, new LinkKey(LINK1_ID)),
321 .setSource(new org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021
322 .link.attributes.SourceBuilder().setSourceNode(NODE1_ID).setSourceTp(TP1_ID).build())
323 .setDestination(new org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021
324 .link.attributes.DestinationBuilder().setDestNode(NODE2_ID).setDestTp(TP2_ID).build())
326 .addAugmentation(new Link1Builder().setSymbolicPathName(LINK1_ID.getValue()).build())