Bug 5030: BGP Application Peer beanchmark app
[bgpcep.git] / bgp / benchmark-app / src / main / java / org / opendaylight / protocol / bgp / benchmark / app / AppPeerBenchmark.java
1 /*
2  * Copyright (c) 2016 Cisco Systems, Inc. and others.  All rights reserved.
3  *
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
7  */
8
9 package org.opendaylight.protocol.bgp.benchmark.app;
10
11 import com.google.common.base.Stopwatch;
12 import com.google.common.net.InetAddresses;
13 import java.util.Collections;
14 import java.util.concurrent.Future;
15 import java.util.concurrent.TimeUnit;
16 import org.opendaylight.controller.md.sal.binding.api.BindingTransactionChain;
17 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
18 import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
19 import org.opendaylight.controller.md.sal.common.api.data.AsyncTransaction;
20 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
21 import org.opendaylight.controller.md.sal.common.api.data.TransactionChain;
22 import org.opendaylight.controller.md.sal.common.api.data.TransactionChainListener;
23 import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
24 import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.RpcRegistration;
25 import org.opendaylight.controller.sal.binding.api.RpcProviderRegistry;
26 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Ipv4Address;
27 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Ipv4Prefix;
28 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.inet.rev150305.application.rib.tables.routes.Ipv4RoutesCaseBuilder;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.inet.rev150305.ipv4.routes.Ipv4Routes;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.inet.rev150305.ipv4.routes.Ipv4RoutesBuilder;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.inet.rev150305.ipv4.routes.ipv4.routes.Ipv4Route;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.inet.rev150305.ipv4.routes.ipv4.routes.Ipv4RouteBuilder;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.inet.rev150305.ipv4.routes.ipv4.routes.Ipv4RouteKey;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev130919.PathId;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev130919.path.attributes.Attributes;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev130919.path.attributes.AttributesBuilder;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev130919.path.attributes.attributes.AsPath;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev130919.path.attributes.attributes.AsPathBuilder;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev130919.path.attributes.attributes.LocalPref;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev130919.path.attributes.attributes.LocalPrefBuilder;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev130919.path.attributes.attributes.MultiExitDisc;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev130919.path.attributes.attributes.MultiExitDiscBuilder;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev130919.path.attributes.attributes.Origin;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev130919.path.attributes.attributes.OriginBuilder;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.ApplicationRib;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.ApplicationRibBuilder;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.ApplicationRibId;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.ApplicationRibKey;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.rib.Tables;
50 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.rib.TablesBuilder;
51 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.rib.TablesKey;
52 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev130919.BgpOrigin;
53 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev130919.Ipv4AddressFamily;
54 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev130919.UnicastSubsequentAddressFamily;
55 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev130919.next.hop.c.next.hop.Ipv4NextHopCaseBuilder;
56 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev130919.next.hop.c.next.hop.ipv4.next.hop._case.Ipv4NextHopBuilder;
57 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.odl.bgp.app.peer.benchmark.rev160309.AddPrefixInput;
58 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.odl.bgp.app.peer.benchmark.rev160309.AddPrefixOutput;
59 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.odl.bgp.app.peer.benchmark.rev160309.AddPrefixOutputBuilder;
60 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.odl.bgp.app.peer.benchmark.rev160309.DeletePrefixInput;
61 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.odl.bgp.app.peer.benchmark.rev160309.DeletePrefixOutput;
62 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.odl.bgp.app.peer.benchmark.rev160309.DeletePrefixOutputBuilder;
63 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.odl.bgp.app.peer.benchmark.rev160309.OdlBgpAppPeerBenchmarkService;
64 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.odl.bgp.app.peer.benchmark.rev160309.output.Result;
65 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.odl.bgp.app.peer.benchmark.rev160309.output.ResultBuilder;
66 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
67 import org.opendaylight.yangtools.yang.binding.KeyedInstanceIdentifier;
68 import org.opendaylight.yangtools.yang.common.RpcResult;
69 import org.opendaylight.yangtools.yang.common.RpcResultBuilder;
70 import org.slf4j.Logger;
71 import org.slf4j.LoggerFactory;
72
73 public class AppPeerBenchmark implements OdlBgpAppPeerBenchmarkService, TransactionChainListener, AutoCloseable {
74
75     private static final Logger LOG = LoggerFactory.getLogger(AppPeerBenchmark.class);
76
77     private static final AsPath AS_PATH = new AsPathBuilder().build();
78     private static final Origin ORIGIN = new OriginBuilder().setValue(BgpOrigin.Igp).build();
79     private static final MultiExitDisc MED = new MultiExitDiscBuilder().setMed(0L).build();
80     private static final LocalPref LOC_PREF = new LocalPrefBuilder().setPref(100L).build();
81
82     private static final String SLASH = "/";
83     private static final String PREFIX = SLASH + "32";
84
85     private static final PathId PATH_ID = new PathId(0L);
86
87     private final BindingTransactionChain txChain;
88     private final RpcRegistration<OdlBgpAppPeerBenchmarkService> rpcRegistration;
89     private final InstanceIdentifier<ApplicationRib> iid;
90     private final InstanceIdentifier<Ipv4Routes> routesIId;
91
92     public AppPeerBenchmark(final DataBroker bindingDataBroker, final RpcProviderRegistry rpcProviderRegistry,
93             final String appRibId) {
94         this.txChain = bindingDataBroker.createTransactionChain(this);
95         this.iid = initTable(appRibId);
96         final InstanceIdentifier tablesIId = this.iid
97                 .child(Tables.class, new TablesKey(Ipv4AddressFamily.class, UnicastSubsequentAddressFamily.class));
98         this.routesIId = tablesIId.child(Ipv4Routes.class);
99         this.rpcRegistration = rpcProviderRegistry.addRpcImplementation(OdlBgpAppPeerBenchmarkService.class, this);
100         LOG.info("BGP Application Peer Benchmark Application started.");
101     }
102
103     @Override
104     public void onTransactionChainFailed(final TransactionChain<?, ?> chain, final AsyncTransaction<?, ?> transaction,
105             final Throwable cause) {
106         LOG.error("Broken chain {} in DatastoreBaAbstractWrite, transaction {}, cause {}", chain,
107                 transaction.getIdentifier(), cause);
108     }
109
110     @Override
111     public void onTransactionChainSuccessful(final TransactionChain<?, ?> chain) {
112         LOG.debug("DatastoreBaAbstractWrite closed successfully, chain {}", chain);
113     }
114
115     private InstanceIdentifier<ApplicationRib> initTable(final String appRibId) {
116         final Tables tables = new TablesBuilder()
117                 .setAfi(Ipv4AddressFamily.class)
118                 .setSafi(UnicastSubsequentAddressFamily.class)
119                 .setRoutes(
120                         new Ipv4RoutesCaseBuilder().setIpv4Routes(
121                                 new Ipv4RoutesBuilder().setIpv4Route(Collections.<Ipv4Route> emptyList()).build())
122                                 .build()).build();
123
124         final ApplicationRib appRib = new ApplicationRibBuilder()
125                 .setId(new ApplicationRibId(new ApplicationRibId(appRibId)))
126                 .setTables(Collections.singletonList(tables)).build();
127
128         final InstanceIdentifier<ApplicationRib> iid = KeyedInstanceIdentifier.builder(ApplicationRib.class,
129                 new ApplicationRibKey(new ApplicationRibId(appRibId))).build();
130         final WriteTransaction wTx = this.txChain.newWriteOnlyTransaction();
131         wTx.put(LogicalDatastoreType.CONFIGURATION, iid, appRib);
132         wTx.submit();
133         return iid;
134     }
135
136     @Override
137     public Future<RpcResult<AddPrefixOutput>> addPrefix(final AddPrefixInput input) {
138         final long duration = addRoute(input.getPrefix(), input.getNexthop(), input.getCount(), input.getBatchsize());
139         final long rate = countRate(duration, input.getCount());
140
141         final AddPrefixOutputBuilder outputbuilder = new AddPrefixOutputBuilder();
142         outputbuilder.setResult(createResult(input.getCount(), duration, rate));
143         final AddPrefixOutput output = outputbuilder.build();
144         return RpcResultBuilder.success(output).buildFuture();
145     }
146
147     @Override
148     public Future<RpcResult<DeletePrefixOutput>> deletePrefix(final DeletePrefixInput input) {
149         final long duration = deleteRoute(input.getPrefix(), input.getCount(), input.getBatchsize());
150         final long rate = countRate(duration, input.getCount());
151
152         final DeletePrefixOutputBuilder outputbuilder = new DeletePrefixOutputBuilder();
153         outputbuilder.setResult(createResult(input.getCount(), duration, rate));
154         final DeletePrefixOutput output = outputbuilder.build();
155         return RpcResultBuilder.success(output).buildFuture();
156     }
157
158     @Override
159     public void close() {
160         this.rpcRegistration.close();
161         final WriteTransaction dTx = this.txChain.newWriteOnlyTransaction();
162         dTx.delete(LogicalDatastoreType.CONFIGURATION, this.iid);
163         try {
164             dTx.submit().checkedGet();
165         } catch (final TransactionCommitFailedException e) {
166             LOG.warn("Failed to clean-up BGP Application RIB.");
167         }
168         this.txChain.close();
169         LOG.info("BGP Application Peer Benchmark Application closed.");
170     }
171
172     private long addRoute(final Ipv4Prefix ipv4Prefix, final Ipv4Address ipv4Address, final long count, final long batch) {
173         final AttributesBuilder attributesBuilder = new AttributesBuilder();
174         attributesBuilder.setCNextHop(new Ipv4NextHopCaseBuilder().setIpv4NextHop(
175                 new Ipv4NextHopBuilder().setGlobal(new Ipv4Address(ipv4Address)).build()).build());
176         attributesBuilder.setMultiExitDisc(MED);
177         attributesBuilder.setLocalPref(LOC_PREF);
178         attributesBuilder.setOrigin(ORIGIN);
179         attributesBuilder.setAsPath(AS_PATH);
180         final Attributes attributes = attributesBuilder.build();
181         return processRoutes(ipv4Prefix, count, batch, attributes);
182     }
183
184     private long deleteRoute(final Ipv4Prefix ipv4Prefix, final long count, final long batch) {
185         return processRoutes(ipv4Prefix, count, batch, null);
186     }
187
188     private long processRoutes(final Ipv4Prefix ipv4Prefix, final long count, final long batch, final Attributes attributes) {
189         WriteTransaction wTx = this.txChain.newWriteOnlyTransaction();
190         String address = getAdddressFromPrefix(ipv4Prefix);
191         final Stopwatch stopwatch = Stopwatch.createStarted();
192         for (int i = 1; i <= count; i++) {
193             final Ipv4RouteKey routeKey = new Ipv4RouteKey(PATH_ID, createPrefix(address));
194             final KeyedInstanceIdentifier<Ipv4Route, Ipv4RouteKey> routeIId = this.routesIId.child(Ipv4Route.class, routeKey);
195             if (attributes != null) {
196                 final Ipv4RouteBuilder ipv4RouteBuilder = new Ipv4RouteBuilder();
197                 ipv4RouteBuilder.setPrefix(routeKey.getPrefix());
198                 ipv4RouteBuilder.setKey(routeKey);
199                 ipv4RouteBuilder.setAttributes(attributes);
200                 final Ipv4Route ipv4Route = ipv4RouteBuilder.build();
201                 wTx.put(LogicalDatastoreType.CONFIGURATION, routeIId,
202                         ipv4Route);
203             } else {
204                 wTx.delete(LogicalDatastoreType.CONFIGURATION, routeIId);
205             }
206             if (i % batch == 0) {
207                 wTx.submit();
208                 wTx = this.txChain.newWriteOnlyTransaction();
209             }
210             address = increasePrefix(address);
211         }
212         wTx.submit();
213         return stopwatch.stop().elapsed(TimeUnit.MILLISECONDS);
214     }
215
216     private static long countRate(final long durationMillis, final long count) {
217         final long durationSec = TimeUnit.MILLISECONDS.toSeconds(durationMillis);
218         if (durationSec != 0) {
219             return count / durationSec;
220         }
221         return count;
222     }
223
224     private static String increasePrefix(final String prefix) {
225         return InetAddresses.increment(InetAddresses.forString(prefix)).getHostAddress();
226     }
227
228     private static Result createResult(final long count, final long duration, final long rate) {
229         return new ResultBuilder().setCount(count).setDuration(duration).setRate(rate).build();
230     }
231
232     private static String getAdddressFromPrefix(final Ipv4Prefix prefix) {
233         return prefix.getValue().split(SLASH)[0];
234     }
235
236     private static Ipv4Prefix createPrefix(final String address) {
237         return new Ipv4Prefix(address + PREFIX);
238     }
239 }