5e069e31e7ee439fb9de43db603c7fefc4d37e50
[bgpcep.git] / bgp / rib-impl / src / main / java / org / opendaylight / protocol / bgp / rib / impl / RIBImpl.java
1 /*
2  * Copyright (c) 2013 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 package org.opendaylight.protocol.bgp.rib.impl;
9
10 import com.google.common.base.Objects;
11 import com.google.common.base.Objects.ToStringHelper;
12 import com.google.common.base.Optional;
13 import com.google.common.base.Preconditions;
14 import com.google.common.collect.ImmutableList;
15 import com.google.common.util.concurrent.FutureCallback;
16 import com.google.common.util.concurrent.Futures;
17 import java.util.Collections;
18 import java.util.List;
19 import java.util.concurrent.ExecutionException;
20 import javax.annotation.concurrent.ThreadSafe;
21 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
22 import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction;
23 import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
24 import org.opendaylight.controller.md.sal.common.api.TransactionStatus;
25 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
26 import org.opendaylight.protocol.bgp.rib.DefaultRibReference;
27 import org.opendaylight.protocol.bgp.rib.impl.spi.BGPDispatcher;
28 import org.opendaylight.protocol.bgp.rib.impl.spi.RIB;
29 import org.opendaylight.protocol.bgp.rib.spi.AdjRIBsIn;
30 import org.opendaylight.protocol.bgp.rib.spi.Peer;
31 import org.opendaylight.protocol.bgp.rib.spi.RIBExtensionConsumerContext;
32 import org.opendaylight.protocol.framework.ReconnectStrategyFactory;
33 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.AsNumber;
34 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Ipv4Address;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev130919.Update;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev130919.UpdateBuilder;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev130919.update.Nlri;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev130919.update.PathAttributes;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev130919.update.WithdrawnRoutes;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.BgpTableType;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.PathAttributes1;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.PathAttributes2;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.destination.destination.type.DestinationIpv4CaseBuilder;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.destination.destination.type.destination.ipv4._case.DestinationIpv4Builder;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.update.path.attributes.MpReachNlri;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.update.path.attributes.MpReachNlriBuilder;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.update.path.attributes.MpUnreachNlri;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.update.path.attributes.MpUnreachNlriBuilder;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.update.path.attributes.mp.reach.nlri.AdvertizedRoutesBuilder;
50 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.update.path.attributes.mp.unreach.nlri.WithdrawnRoutesBuilder;
51 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.BgpRib;
52 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.BgpRibBuilder;
53 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.RibId;
54 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.bgp.rib.Rib;
55 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.bgp.rib.RibBuilder;
56 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.bgp.rib.RibKey;
57 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.bgp.rib.rib.LocRibBuilder;
58 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.rib.Tables;
59 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.rib.TablesKey;
60 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev130919.Ipv4AddressFamily;
61 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev130919.UnicastSubsequentAddressFamily;
62 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
63 import org.opendaylight.yangtools.yang.common.RpcResult;
64 import org.slf4j.Logger;
65 import org.slf4j.LoggerFactory;
66
67 @ThreadSafe
68 public final class RIBImpl extends DefaultRibReference implements AutoCloseable, RIB {
69     private static final Logger LOG = LoggerFactory.getLogger(RIBImpl.class);
70     private static final Update EOR = new UpdateBuilder().build();
71     private static final TablesKey IPV4_UNICAST_TABLE = new TablesKey(Ipv4AddressFamily.class, UnicastSubsequentAddressFamily.class);
72     private final ReconnectStrategyFactory tcpStrategyFactory;
73     private final ReconnectStrategyFactory sessionStrategyFactory;
74     private final BGPDispatcher dispatcher;
75     private final DataBroker dps;
76     private final AsNumber localAs;
77     private final Ipv4Address bgpIdentifier;
78     private final List<BgpTableType> localTables;
79     private final RIBTables tables;
80
81     public RIBImpl(final RibId ribId, final AsNumber localAs, final Ipv4Address localBgpId, final RIBExtensionConsumerContext extensions,
82             final BGPDispatcher dispatcher, final ReconnectStrategyFactory tcpStrategyFactory,
83             final ReconnectStrategyFactory sessionStrategyFactory, final DataBroker dps, final List<BgpTableType> localTables) {
84         super(InstanceIdentifier.builder(BgpRib.class).child(Rib.class, new RibKey(Preconditions.checkNotNull(ribId))).toInstance());
85         this.dps = Preconditions.checkNotNull(dps);
86         this.localAs = Preconditions.checkNotNull(localAs);
87         this.bgpIdentifier = Preconditions.checkNotNull(localBgpId);
88         this.dispatcher = Preconditions.checkNotNull(dispatcher);
89         this.sessionStrategyFactory = Preconditions.checkNotNull(sessionStrategyFactory);
90         this.tcpStrategyFactory = Preconditions.checkNotNull(tcpStrategyFactory);
91         this.localTables = ImmutableList.copyOf(localTables);
92         this.tables = new RIBTables(extensions);
93
94         LOG.debug("Instantiating RIB table {} at {}", ribId, getInstanceIdentifier());
95
96         final ReadWriteTransaction trans = dps.newReadWriteTransaction();
97         Optional<Rib> o;
98         try {
99             o = trans.read(LogicalDatastoreType.OPERATIONAL, getInstanceIdentifier()).get();
100         } catch (InterruptedException | ExecutionException e) {
101             throw new IllegalStateException("Failed to read topology", e);
102         }
103         Preconditions.checkState(!o.isPresent(), "Data provider conflict detected on object {}", getInstanceIdentifier());
104
105         // put empty BgpRib if not exists
106         trans.merge(LogicalDatastoreType.OPERATIONAL, InstanceIdentifier.builder(BgpRib.class).build(), new BgpRibBuilder().build());
107         trans.put(LogicalDatastoreType.OPERATIONAL, getInstanceIdentifier(), new RibBuilder().setKey(new RibKey(ribId)).setId(ribId).setLocRib(
108                 new LocRibBuilder().setTables(Collections.<Tables> emptyList()).build()).build());
109
110         for (BgpTableType t : localTables) {
111             final TablesKey key = new TablesKey(t.getAfi(), t.getSafi());
112             if (this.tables.create(trans, this, key) == null) {
113                 LOG.debug("Did not create local table for unhandled table type {}", t);
114             }
115         }
116
117         Futures.addCallback(trans.commit(), new FutureCallback<RpcResult<TransactionStatus>>() {
118             @Override
119             public void onSuccess(final RpcResult<TransactionStatus> result) {
120                 LOG.trace("Change committed successfully");
121             }
122
123             @Override
124             public void onFailure(final Throwable t) {
125                 LOG.error("Failed to initiate RIB {}", getInstanceIdentifier());
126             }
127         });
128     }
129
130     synchronized void initTables(final byte[] remoteBgpId) {
131     }
132
133     @Override
134     public synchronized void updateTables(final Peer peer, final Update message) {
135         final WriteTransaction trans = this.dps.newWriteOnlyTransaction();
136
137         if (!EOR.equals(message)) {
138             final WithdrawnRoutes wr = message.getWithdrawnRoutes();
139             if (wr != null) {
140                 final AdjRIBsIn ari = this.tables.get(IPV4_UNICAST_TABLE);
141                 if (ari != null) {
142                     ari.removeRoutes(
143                             trans,
144                             peer,
145                             new MpUnreachNlriBuilder().setAfi(Ipv4AddressFamily.class).setSafi(UnicastSubsequentAddressFamily.class).setWithdrawnRoutes(
146                                     new WithdrawnRoutesBuilder().setDestinationType(
147                                             new DestinationIpv4CaseBuilder().setDestinationIpv4(
148                                                     new DestinationIpv4Builder().setIpv4Prefixes(wr.getWithdrawnRoutes()).build()).build()).build()).build());
149                 } else {
150                     LOG.debug("Not removing objects from unhandled IPv4 Unicast");
151                 }
152             }
153
154             final PathAttributes attrs = message.getPathAttributes();
155             if (attrs != null) {
156                 final PathAttributes2 mpu = attrs.getAugmentation(PathAttributes2.class);
157                 if (mpu != null) {
158                     final MpUnreachNlri nlri = mpu.getMpUnreachNlri();
159
160                     final AdjRIBsIn ari = this.tables.get(new TablesKey(nlri.getAfi(), nlri.getSafi()));
161                     if (ari != null) {
162                         ari.removeRoutes(trans, peer, nlri);
163                     } else {
164                         LOG.debug("Not removing objects from unhandled NLRI {}", nlri);
165                     }
166                 }
167             }
168
169             final Nlri ar = message.getNlri();
170             if (ar != null) {
171                 final AdjRIBsIn ari = this.tables.get(IPV4_UNICAST_TABLE);
172                 if (ari != null) {
173                     final MpReachNlriBuilder b = new MpReachNlriBuilder().setAfi(Ipv4AddressFamily.class).setSafi(
174                             UnicastSubsequentAddressFamily.class).setAdvertizedRoutes(
175                                     new AdvertizedRoutesBuilder().setDestinationType(
176                                             new DestinationIpv4CaseBuilder().setDestinationIpv4(
177                                                     new DestinationIpv4Builder().setIpv4Prefixes(ar.getNlri()).build()).build()).build());
178                     if (attrs != null) {
179                         b.setCNextHop(attrs.getCNextHop());
180                     }
181
182                     ari.addRoutes(trans, peer, b.build(), attrs);
183                 } else {
184                     LOG.debug("Not adding objects from unhandled IPv4 Unicast");
185                 }
186             }
187
188             if (attrs != null) {
189                 final PathAttributes1 mpr = attrs.getAugmentation(PathAttributes1.class);
190                 if (mpr != null) {
191                     final MpReachNlri nlri = mpr.getMpReachNlri();
192
193                     final AdjRIBsIn ari = this.tables.get(new TablesKey(nlri.getAfi(), nlri.getSafi()));
194                     if (ari != null) {
195                         if (message.equals(ari.endOfRib())) {
196                             ari.markUptodate(trans, peer);
197                         } else {
198                             ari.addRoutes(trans, peer, nlri, attrs);
199                         }
200                     } else {
201                         LOG.debug("Not adding objects from unhandled NLRI {}", nlri);
202                     }
203                 }
204             }
205         } else {
206             final AdjRIBsIn ari = this.tables.get(IPV4_UNICAST_TABLE);
207             if (ari != null) {
208                 ari.markUptodate(trans, peer);
209             } else {
210                 LOG.debug("End-of-RIB for IPv4 Unicast ignored");
211             }
212         }
213
214         Futures.addCallback(trans.commit(), new FutureCallback<RpcResult<TransactionStatus>>() {
215             @Override
216             public void onSuccess(final RpcResult<TransactionStatus> result) {
217                 LOG.debug("RIB modification successfully committed.");
218             }
219
220             @Override
221             public void onFailure(final Throwable t) {
222                 LOG.error("Failed to commit RIB modification", t);
223             }
224         });
225     }
226
227     @Override
228     public synchronized void clearTable(final Peer peer, final TablesKey key) {
229         final AdjRIBsIn ari = this.tables.get(key);
230         if (ari != null) {
231             final WriteTransaction trans = this.dps.newWriteOnlyTransaction();
232             ari.clear(trans, peer);
233
234             Futures.addCallback(trans.commit(), new FutureCallback<RpcResult<TransactionStatus>>() {
235                 @Override
236                 public void onSuccess(final RpcResult<TransactionStatus> result) {
237                     // Nothing to do
238                 }
239
240                 @Override
241                 public void onFailure(final Throwable t) {
242                     LOG.error("Failed to commit RIB modification", t);
243                 }
244             });
245         }
246     }
247
248     @Override
249     public String toString() {
250         return addToStringAttributes(Objects.toStringHelper(this)).toString();
251     }
252
253     protected ToStringHelper addToStringAttributes(final ToStringHelper toStringHelper) {
254         return toStringHelper;
255     }
256
257     @Override
258     public void close() throws InterruptedException, ExecutionException {
259         final WriteTransaction t = this.dps.newWriteOnlyTransaction();
260         t.delete(LogicalDatastoreType.OPERATIONAL, getInstanceIdentifier());
261         t.commit().get();
262     }
263
264     @Override
265     public AsNumber getLocalAs() {
266         return this.localAs;
267     }
268
269     @Override
270     public Ipv4Address getBgpIdentifier() {
271         return this.bgpIdentifier;
272     }
273
274     @Override
275     public List<? extends BgpTableType> getLocalTables() {
276         return this.localTables;
277     }
278
279     @Override
280     public ReconnectStrategyFactory getTcpStrategyFactory() {
281         return this.tcpStrategyFactory;
282     }
283
284     @Override
285     public ReconnectStrategyFactory getSessionStrategyFactory() {
286         return this.sessionStrategyFactory;
287     }
288
289     @Override
290     public BGPDispatcher getDispatcher() {
291         return this.dispatcher;
292     }
293
294     @Override
295     public void initTable(final Peer bgpPeer, final TablesKey key) {
296         // FIXME: BUG-196: support graceful restart
297     }
298 }